﻿WEBVTT

00:00:00.000 --> 00:00:06.000
Translated by visionNoob, KNU
https://github.com/insurgent92/CS231N_17_KOR_SUB

00:00:10.512 --> 00:00:15.376
좋은 아침입니다.
12시 3분이군요. 수업을 진행하겠습니다.

00:00:15.376 --> 00:00:18.014
CS231n 12강입니다.

00:00:18.014 --> 00:00:21.840
오늘은 CNN의 시각화와 이해에 대해서 배워볼 것입니다.

00:00:21.840 --> 00:00:25.270
12강은 이미지 자료가 아주 많아서
아주 재미있는 수업이 될 것입니다.

00:00:25.270 --> 00:00:28.375
제가 가장 좋아하는 강의입니다.

00:00:28.375 --> 00:00:30.354
우선 몇 가지 공지사항을 전달해 드리겠습니다.

00:00:30.354 --> 00:00:39.544
프로젝트는 잘 진행하고 계신가요? 오늘 밤 까지
Canvas에 마일스톤을 제출해 주셔야 합니다.

00:00:39.545 --> 00:00:43.590
그리고 현재 중간고사를 채점 중입니다.

00:00:43.590 --> 00:00:49.537
아마도 채점 결과는 Gradescope를 통해서
이번 주 이내로 확인해 보실 수 있을 것입니다.

00:00:49.537 --> 00:00:54.987
지난 주에 여러분께서 Gradescope 가입과
관련해서 많이 혼란스러우셨을 것입니다.

00:00:54.988 --> 00:00:57.372
Piazza에서 이와 관련된 질문들을 많이 받았습니다.

00:00:57.372 --> 00:01:02.973
중간고사 채점 결과를 Gradescope를 통해서 발표하기로
결정했습니다. 관련 메일을 받으시면 잘 확인해 주시기 바랍니다.

00:01:02.973 --> 00:01:07.412
그리고 지난 주 금요일에 과제 3이 출제 되었습니다.

00:01:07.412 --> 00:01:11.088
과제 3은 지난 주 금요일부터 1주일 후인 26일 까지 입니다.

00:01:11.088 --> 00:01:14.444
과제3은 지난 해와 비교해서 완전히 달라졌습니다.

00:01:14.444 --> 00:01:18.847
과제3을 예정보다 늦게 출제해 드려서 사과의 말씀 드립니다.

00:01:18.847 --> 00:01:25.283
하지만 과제3은 아주 재밌을 것입니다. 오늘 강의에서
배운 내용들을 실제로 구현하게 될 것입니다.

00:01:25.283 --> 00:01:30.921
과제3을 하시려면 PyTorch/Tensor Flow
중에서 선택하시면 됩니다.

00:01:30.921 --> 00:01:34.512
이번 과제가 여러분들에게 의미있는 경험이 되었으면 좋겠습니다.

00:01:34.512 --> 00:01:37.273
그리고 주말 동안 많은 분들이
HyperQuest 활동을 해주셨습니다.

00:01:37.273 --> 00:01:40.549
아주 놀라웠습니다. 리더보드가 어제 생겼는데

00:01:40.549 --> 00:01:47.402
많은 분들이 Deep learning/ Neural network을
학습시키는 스킬들을 마음껏 뽐내 주셨습니다. 대단합니다.

00:01:47.402 --> 00:01:55.118
HyperQuest의 많은 분들의 성원 가운데 마일스톤 제출기한이
HyperQuest와 겹치는 부분이 있었기 때문에

00:01:55.118 --> 00:01:58.591
Extra credit을 드리는 HyperQuest 마감일을
일요일까지 연장하기로 했습니다.

00:01:58.591 --> 00:02:04.773
따라서 일요일 까지 HyperQuest를 12회 이상
실행하신 모든 분들에게 extra credit을 지급할 예정입니다.

00:02:04.773 --> 00:02:11.200
그리고 리더보드의 상위권에 위치하신 분들은
조금 더 많은 credit을 받게될 것입니다.

00:02:11.200 --> 00:02:15.935
HyperQuest에 많은 관심에 감사드리며
아주 뜻깊은 시간인 것 같습니다.

00:02:15.935 --> 00:02:17.844
마지막 공지사항은 poster session 관련 공지입니다.

00:02:17.844 --> 00:02:21.445
6월 6일에 poster session이 있습니다.

00:02:21.445 --> 00:02:25.932
6월 6일이 거의 확정일 것입니다. 정확한 시간은
기억이 안나지만, 6월 6일은 확실합니다.

00:02:25.932 --> 00:02:31.897
종강 후 여행이나 인턴쉽을 준비하고 있는 많은
분들이 poster session 일정을 문의해 주셨습니다.

00:02:31.897 --> 00:02:35.497
poster session은 6월 6일입니다.

00:02:35.497 --> 00:02:41.171
공지사항에 대한 문의사항 있으십니까?
없으면 수업 진행하겠습니다.

00:02:41.171 --> 00:02:48.161
지난 시간에는 다양한
Computer Vision Tasks를 살펴보았습니다.

00:02:48.161 --> 00:02:54.318
우선 Semantic segmentation을 배웠습니다. 입력 이미지의
모든 픽셀에 레이블링을 하는 문제였습니다.

00:02:54.318 --> 00:02:58.225
하지만 Semantic Segmentation은
이미지 내의 객체들을 구분할 수 없었습니다.

00:02:58.225 --> 00:03:00.773
그리고 Classification + Localization을 배웠습니다.

00:03:00.773 --> 00:03:06.539
이 문제는 이미지에 레이블을 부여하는 것 뿐만 아니라
객체의 정확한 위치의 BBox도 알아내야 했습니다.

00:03:06.539 --> 00:03:12.594
Classification + Localization 문제에서는 이미지 내에
알아내야 하는 객체의 수가 정해져 있었습니다.

00:03:12.594 --> 00:03:16.785
Classification + Localization을 응용해서
Pose recognition을 할 수 있었습니다.

00:03:16.785 --> 00:03:20.222
사람의 관절의 위치를 regression 문제로 푸는 방법이었죠

00:03:20.222 --> 00:03:27.102
Object Detection도 배웠습니다. 개, 고양이 처럼
고정된 category labels이 있었습니다.

00:03:27.102 --> 00:03:32.769
그리고 이미지 내에 모든 객체의 위치에
BBox를 그려 넣어야 했습니다.

00:03:32.769 --> 00:03:37.063
Object Detection은 Classification +
Localization 문제와는 다른 문제였습니다.

00:03:37.063 --> 00:03:42.298
Object Detection 문제에서는 이미지 내에 객체의
수가 얼마나 있는지 미리 알 수 없었습니다.

00:03:42.298 --> 00:03:52.588
R-CNN, Fast R-CNN, Faster R-CNN 패밀리를 배웠습니다.
그리고 single shot detection 도 배웠죠(YOLO, SSD)

00:03:52.588 --> 00:03:57.722
그리고 Instatnce Segmentation에 대해서도
간단하게 배워 보았습니다.

00:03:57.722 --> 00:04:01.164
Semantic segmentation과 Object Detection을
결합시킨 방법이었습니다.

00:04:01.164 --> 00:04:04.934
Instance Segmentation의 목표는 우선
우리가 관심있는 카테고리에 속하는 모든 객체를 찾아내고

00:04:04.934 --> 00:04:07.997
각 객체가 속하는 픽셀을 레이블링하는 문제였습니다.

00:04:07.997 --> 00:04:14.887
가령 이 예제에서는 2마리의 개와 1마리의 고양이가 있으며
객 객체가 속하는 픽셀을 레이블링해야 합니다.

00:04:14.887 --> 00:04:23.810
지난 시간에도 재미있는 Tasks들을 많이 다루긴 했지만
여러분이 프로젝트에 추가할만한 아주 많은 것들이 존재합니다.

00:04:23.810 --> 00:04:27.081
오늘은 주제를 조금 바꿔보도록 하겠습니다.

00:04:27.081 --> 00:04:30.578
과연 convolutional networks 내부에서는
어떤 일이 일어나고 있는 것일까요?

00:04:30.578 --> 00:04:34.120
지금까지는 CNN을 어떻게 학습시킬 것인지를 배웠습니다.

00:04:34.120 --> 00:04:37.503
그리고 다양한 문제를 풀기 위해서 CNN 아키텍쳐를
어떻게 설계하고 조합해야하는지를 배웠습니다.

00:04:37.503 --> 00:04:42.653
자 이제 여러분이 해 볼만한 질문은 바로
CNN의 내부는 어떻게 생겼을지 입니다.

00:04:42.653 --> 00:04:44.081
CNN은 이런 문제들을 어떻게 해결하는 것일까요?

00:04:44.081 --> 00:04:46.444
CNN이 어떤 종류의 Features를 찾고있는 것일까요?

00:04:46.444 --> 00:04:48.612
이와 같은 질문들 말입니다.

00:04:48.612 --> 00:04:53.399
지금까지는 ConvNets을 Black box라고 생각했습니다.

00:04:53.399 --> 00:04:57.100
CNN의 한 쪽에서는 입력 이미지가 들어갑니다.

00:04:57.100 --> 00:05:01.170
그리고 Conv Layers를 거치면서
아주 다양한 변환을 거치게 됩니다.

00:05:01.170 --> 00:05:07.363
결국 CNN의 출력 값은 우리가 이해하고 해석할 수 있는
Class scores의 형태로 나오는 것입니다.

00:05:07.363 --> 00:05:12.342
Class scores 뿐만 아니라 Bounding Box의 위치,
Labeled pixels 와 같은 형태의 출력도 있을 것입니다.

00:05:12.342 --> 00:05:15.933
그럼 CNN의 중간 과정에서는 무슨 일이 일어나는 것일까요?

00:05:15.933 --> 00:05:18.567
CNN이 입력 이미지에서 찾고있는 것은 무엇일까요?

00:05:18.567 --> 00:05:24.364
ConvNets은 어떻게 동작할까요? CNN이 도대체
이미지에서 어떤 종류의 것들을 찾고있는 걸까요?

00:05:24.364 --> 00:05:29.327
CNN의 내부를 분석하려면 어떤 테크닉이 필요할까요?

00:05:29.327 --> 00:05:34.522
우선 가장 만만하게 접근해 볼 수 있는 것은
첫 번째 Layer 입니다.

00:05:34.522 --> 00:05:41.492
우선 AlexNet의 예시를 살펴보겠습니다.

00:05:41.492 --> 00:05:45.193
AlexNet의 첫 번째 Conv Layers에는
많은 필터들이 있습니다.

00:05:45.193 --> 00:05:49.230
AlexNet의 각 Conv filter는
3 x 11 x 11의 형태를 취하고 있습니다.

00:05:49.230 --> 00:05:52.268
Conv filters는 sliding window로
이미지를 돕니다.

00:05:52.268 --> 00:05:54.947
그리고 이미지의 일부 영역과 내적을 수행합니다.

00:05:54.947 --> 00:06:01.729
이렇게 필터의 가중치와 내적한 결과가
첫 번째 Conv Layer의 출력입니다.

00:06:01.729 --> 00:06:05.074
AlexNet의 첫 번째 레이어에는
64개의 filter가 있습니다.

00:06:05.074 --> 00:06:11.682
첫 번째 Conv Layer는 입력 이미지와
직접 내적을 수행하기 때문에

00:06:11.682 --> 00:06:19.458
이 필터를 단순히 시각화시키는 것 만으로도 이 필터가
이미지에서 무엇을 찾고 있는지 알아낼 수 있습니다.

00:06:19.458 --> 00:06:30.201
AlexNet의 11x11x3 필터는
11x11x3 rgb 이미지로 쉽게 시각화할 수 있습니다.

00:06:30.201 --> 00:06:35.305
필터가 총 64개 이므로
64개의 11x11 이미지를 시각화시킬 수 있습니다.

00:06:35.305 --> 00:06:42.509
지금 보시는 이미지는 PyTorch Model zoo에서
가져온 pretrained model의 필터들입니다.

00:06:42.509 --> 00:06:51.065
AlexNet, ResNet-18, ResNet-101,DenseNet-121
의 첫 번째 Conv filter의 가중치들 입니다.

00:06:51.065 --> 00:06:55.553
이를 통해서 이 필터들이 무엇을
찾고있는지 알 수 있습니다.

00:06:55.553 --> 00:07:01.052
우선 가장 많이 찾는 것은 엣지성분 입니다.
흰/검으로 길게 늘어선 필터들이 보이실 것입니다.

00:07:01.052 --> 00:07:09.475
다양한 각도와 위치에서의 보색(oppising colors)도 보입니다.
가령 초록색과 분홍색처럼 말이죠

00:07:09.475 --> 00:07:12.732
주황색과 파랑색의 보색도 보입니다.

00:07:12.732 --> 00:07:17.907
학습된 필터를 살펴보면 첫 강의에서 살펴본
hubel and wiesel의 실험이 떠오릅니다.

00:07:17.907 --> 00:07:24.978
인간의 시각 체계에서도 Oriented edges를 감지한다고
알려져 있습니다. 초기 레이어에서 말이죠

00:07:24.978 --> 00:07:31.566
CNN의 첫 번째 layer에서도 비슷한 일이 일어나는 것 같습니다.

00:07:31.566 --> 00:07:46.389
흥미롭게도, CNN을 어떤 모델/데이터로 학습하건 간에
첫 번째 레이어는 전부 다 이런 식으로 생겼다는 점입니다.

00:07:46.389 --> 00:07:51.539
입력 이미지에서 oriented edges 라던지
보색(opposing colors) 같은 것들을 찾는 것입니다.

00:07:51.539 --> 00:07:53.696
질문 있나요?

00:08:04.215 --> 00:08:07.592
네. 이 이 이미지들을 CNN Layer의
학습된 가중치 입니다.

00:08:15.766 --> 00:08:21.318
질문은 "필터의 가중치를 시각화한다고 해서
필터가 무엇을 찾고있는지 알 수 있는지" 입니다.

00:08:21.318 --> 00:08:25.045
이는 Templete Matching 이나 내적을
생각하시면 됩니다.

00:08:25.045 --> 00:08:28.389
가령 여러분이 Templete vecter를 가지고있다고 해봅시다.

00:08:28.389 --> 00:08:35.044
이 Templete Vector와 임의의 데이터를 내적해서
어떤 Scaler output을 계산합니다.

00:08:35.044 --> 00:08:43.062
필터 값을 가장 활성화시키는 입력을 생각해보면
입력 값고 필터의 가중치 값이 동일한 경우입니다.

00:08:43.062 --> 00:08:52.506
내적을 생각해보면, 내적 값을 최대화 시키려면
동일한 값 두 개를 내적하는 것입니다.

00:08:52.506 --> 00:08:57.902
그렇게 때문에 첫 번째 레이어의 가중치를 시각화시키면
첫 번째 레이어가 무엇을 찾고 있는지 알 수 있는 것입니다.

00:09:06.008 --> 00:09:10.052
그리고 이 첫 번쨰 레이어는
Convolutional Layer 입니다.

00:09:10.052 --> 00:09:18.178
이미지를 입력으로 받는 CNN은 일반적으로
첫 번째 레이어가 Conv Layer입니다.

00:09:28.086 --> 00:09:32.118
다음 질문은 "네트워크의 중간에도
이런 시각화를 동일하게 적용할 수 있는지" 입니다.

00:09:32.118 --> 00:09:35.104
바로 다음 슬라이드가 그 내용입니다. :D

00:09:35.104 --> 00:09:41.753
앞서 했던 동일한 시각화 기법을 중간 Conv Layers에
적용하면, 우리가 보고 해석하기 더 어렵습니다.

00:09:41.753 --> 00:09:45.081
지금 보시는 것이 동일한 시각화 기법을 적용한 것입니다.

00:09:45.081 --> 00:09:51.890
현재 보시는 슬라이드는 우리 웹사이트에 있는
작은 ConvNets demo network입니다.

00:09:51.890 --> 00:09:55.987
이 네트워크에서 첫 번째 레이어는
7 x 7 필터 16개 입니다.

00:09:55.987 --> 00:10:00.842
앞선 슬라이드에서 시각화로 보여드렸던
첫 번째 레이어와 동일합니다.

00:10:00.842 --> 00:10:06.583
이제는 두 번째 레이어의 가중치들을 살펴봅시다.
두 번째 레이어까지는 수 차례 Conv &amp; ReLU를 거쳐야 합니다.

00:10:06.583 --> 00:10:10.629
두 번째 Conv Layer는 16채널의 입력을 받습니다.

00:10:10.629 --> 00:10:15.116
그리고 20개의 7x7 conv filters가 있습니다.

00:10:15.116 --> 00:10:20.495
이 필터들은 직접적으로 이미지의 형태로
시각화시킬 수 없다는 문제점이 있습니다.

00:10:20.495 --> 00:10:23.846
어쨌든 시도는 해볼 수 있겠죠

00:10:23.846 --> 00:10:28.547
이 예시에서는 입력은 16 depth를 가지고 있습니다.

00:10:28.547 --> 00:10:40.924
그리고 Conv filters의 사이즈는 7 x 7 x 16 입니다.
이런 필터가 20개 있습니다.

00:10:40.924 --> 00:10:47.498
여기서 문제점은 이 필터들을 직접 살펴보는 것
만으로는 이해할만한 정보를 얻기 힘들다는 점입니다.

00:10:47.498 --> 00:10:53.743
여기에 (Layer 2 weights) 두 번째 레이어를 시각화 시켰습니다.
16 x 7 x 7 필터를 시각화하기 위해서는

00:10:53.743 --> 00:11:01.782
16개의 7 x 7 grayscale images로 나눠서 표현해야 합니다.

00:11:01.782 --> 00:11:11.852
중간에 보이시는 Gray scale 이미지들이 바로
두 번째 레이어의 각 필터들의 가중치입니다.

00:11:11.852 --> 00:11:21.046
두 번째 레이어의 출력이 총 20개 이므로
"7 x 7 이미지 16개"가 총 20개 있습니다.

00:11:21.046 --> 00:11:28.638
두 번째 레이어의 convolutional filters를 이미지로
시각화 해보면 이런 식의 특별한 구조들을 보실 수 있습니다.

00:11:28.638 --> 00:11:32.128
그런데 아무리 자세히 봐도 이 필터가 무엇을 찾고 있는건지
적당한 Intuition을 얻기란 힘듭니다.

00:11:32.128 --> 00:11:36.644
아무리 봐도 잘 모르겠는 이유는 이 필터들은
이미지와 직접 연결되어 있지 않기 떄문입니다.

00:11:36.644 --> 00:11:41.851
두 번째 레이어의 필터들은 첫 번째 레이어의
출력과 연결되어 있습니다.

00:11:41.851 --> 00:11:50.646
따라서 우리가 시각화한 내용은 "두 번째 레이어의 결과를
최대화시키는 첫 번째 레이어의 출력 패턴이 무엇인지" 입니다.

00:11:50.646 --> 00:11:58.490
하지만 이미지의 관점에서 첫 번째 레이어의 출력이
어떻게 생겼는지 감을 잡고 해석하기한 쉽지 않습니다.

00:11:58.490 --> 00:12:03.556
따라서 네트워크의 중간 레이어의 필터들이 무엇을
찾고있는지를 알아내려면 조금 더 fancy한 기법이 필요합니다.

00:12:03.556 --> 00:12:04.819
질문있나요?

00:12:09.189 --> 00:12:16.552
앞서 슬라이드에 있던 이미지들은
0-255 의 범위로 가중치를 normalize한 것입니다.

00:12:16.552 --> 00:12:22.983
실제 가중치들은 범위가 정해져있지 않습니다.
하지만 시각화를 위해서라면 스케일을 조정해야 합니다.

00:12:22.983 --> 00:12:31.892
그리고 필터만 시각화한 것이지 Bias는 고려하지 않았습니다.
따라서 이 시각화 결과를 있는 그대로 믿으면 안됩니다.

00:12:34.180 --> 00:12:38.391
자 이제는 마지막 레이어를 살펴봅시다.
CNN의 마지막 레이어를 가지고 놀어봅시다.

00:12:38.391 --> 00:12:44.908
CNN의 마지막 레이어는 1000개의 클래스 스코어가 있습니다.
이는 학습 데이터의 predicted scores를 의미합니다.

00:12:44.908 --> 00:12:48.628
이 마지막 레이어 직전에는
Fully Connected Layer가 있습니다.

00:12:48.628 --> 00:12:58.328
가령 AlesNet의 마지막 레이어는 이미지를 표현하는
4096-dim 특징벡터를 입력으로 최종 Class scores를 출력합니다.

00:12:58.328 --> 00:13:07.967
CNN의 마지막 레이어에서 어떤 일이 일어나는 지를
알아보는 것도 시각화의 한 방법이 될 수 있습니다.

00:13:07.967 --> 00:13:18.687
이 방법은 많은 이미지로 CNN을 돌려서
각 이미지에서 나온 4096-dim 특징 벡터를 모두 저장힙니다.

00:13:18.687 --> 00:13:26.075
앞선 방법에서는 첫 번째 Conv Layer를 시각화시켰지만
이제는 마지막 Hidden Layer를 시각화시킬 것입니다.

00:13:26.075 --> 00:13:29.791
여기에서 시도해볼 수 있는 방법 중 하나는
Nearest Neighbor를 이용한 방법입니다.

00:13:29.791 --> 00:13:33.162
맨 왼쪽의 이미지는 Lecture 2에서 본 적 있으실 것입니다.

00:13:33.162 --> 00:13:40.303
CiFAR-10 데이터들의  "이미지 픽셀 공간" 에서의
Nearest  neighbors 였습니다.

00:13:40.303 --> 00:13:48.660
CIFAR-10으로 한 결과를 보시면
유사한 이미지를 잘 찾아내는 것을 알 수 있습니다.

00:13:48.660 --> 00:13:58.917
맨 왼쪽 열이 CIFAR-10 으로 학습시킨 이미지입니다.
오른쪽 5열의 이미지는 Testset이죠

00:13:58.917 --> 00:14:02.446
가령 두 번째 행에 있는 흰색 강아지의 예를 들어보겠습니다.

00:14:02.446 --> 00:14:11.643
픽셀 공간에서의 Nearest neighbors는 흰색 덩어리가 있으면
가깝다고 생각할 것입니다. 굳이 개가 아니라도 말이죠

00:14:11.643 --> 00:14:16.937
이런 식으로 거리가 가까운 이미지들을 시각화해
보는 방법도 시각화 기법이 될 수 있습니다.

00:14:16.937 --> 00:14:27.107
다만 픽셀 공간에서 Nearest neighbors를 계산하는 것이 아니라
CNN에서 나온 4096-dim 특징 벡터 공간에서 계산합니다.

00:14:27.107 --> 00:14:29.987
오른쪽에 예제가 몇 가지 있습니다.

00:14:29.987 --> 00:14:38.338
맨 왼쪽 열은 ImageNet Classification
Dataset의 Test Set입니다.

00:14:38.338 --> 00:14:48.515
그리고 나머지 열 들은 AlexNet의 4096-dim
특징벡터에서 계산한 nearest neighbors 결과입니다.

00:14:48.515 --> 00:14:52.941
이 결과를 보면 확실히 픽셀 공간에서의
nearest neighbors와는 아주 다릅니다.

00:14:52.941 --> 00:14:58.375
"특징 공간에서의  nearest neighbors"의 결과를 보면
서로 픽셀 값의 차이가 큰 경우도 있습니다.

00:14:58.375 --> 00:15:03.031
서로 픽셀 값의 차이는 커도 특징 공간 내에서는
아주 유사한 특성을 지닌다는 것을 알 수 있습니다.

00:15:03.031 --> 00:15:10.484
가령 여기 두번째 줄에 코끼리의 예를 살펴봅시다.
코끼리는 왼쪽에 서있고 그 뒤에는 풀밭이 있습니다.

00:15:10.484 --> 00:15:17.307
테스트 셋의 3번째로 가까운 이미지를 살펴보면
코끼리가 오른쪽에 서 있습니다.

00:15:17.307 --> 00:15:26.942
아주 흥미롭습니다. 코끼리가 왼편에 서 있는 이미지와 오른편에
서 있는 이미지의 픽셀 값은 완전히 다를 것이기 때문입니다.

00:15:26.942 --> 00:15:32.554
하지만 네트워크가 학습한 특징 공간 내에서는
두 이미지는 아주 아까워집니다.

00:15:32.554 --> 00:15:37.975
이는 네트워크가 학습을 통해서 이미지의
semantic content한 특징들을 잘 포착해 낸 결과입니다.

00:15:37.975 --> 00:15:46.192
아주 놀라운 일이죠. 이처럼 Nearest neighbor를 통한
시각화 기법은 어떤 일이 일어나는지 살펴보기에 아주 좋습니다.

00:16:02.617 --> 00:16:04.630
[학생이 질문]

00:16:04.630 --> 00:16:13.942
기본적인 supervised learning 과정에서는 특징공간에서
서로 유사해야한다는 Loss는 없습니다.

00:16:13.942 --> 00:16:21.476
특징 공간에서 서로 유사해야한다고 말해주지 않았는데도
결국은 서로 가까워 진 것입니다.

00:16:21.476 --> 00:16:28.746
하지만 사람들이 "triplet/contrastive loss"
를 네트워크가 추가시켜서 학습하기도 합니다.

00:16:28.746 --> 00:16:37.253
이 losses를 통해 특징 공간에서의 계산이 가능하도록
가정과 제약조건을 마지막 레이어에 추가하는 것입니다.

00:16:37.253 --> 00:16:39.907
하지만 AlexNet의 경우에는 그런 장치가 없습니다.

00:16:44.931 --> 00:16:46.060
문제는 가장 가까운 것이 무엇인지...

00:16:46.060 --> 00:16:48.875
질문은 "마지막 레이어에 nearest neighbor를
적용하려면 어떻게 해야하는지" 입니다.

00:16:48.875 --> 00:16:51.432
우선 이미지를 네트워크에 통과시킵니다.

00:16:51.432 --> 00:16:57.670
뒤에서 두번째에 있는 히든 레이어는
4096-dim 벡터입니다.

00:16:57.670 --> 00:17:01.797
네트워크이 마지막 단에는
FC-Layer가 있었습니다.

00:17:01.797 --> 00:17:06.893
자 그럼 각 이미지들에 해당하는
4096-dim 벡터들을 전부 다 저장해 놓습니다.

00:17:06.894 --> 00:17:12.966
그리고 저장된 4096-dim 벡터들을 가지고
nearest neighbors를 계산합니다.

00:17:17.012 --> 00:17:19.171
수업이 끝나고 다시한번 말씀드리죠

00:17:19.171 --> 00:17:28.434
최종 레이어에서 어떤 일이 벌어지는지를 시각화하고자 할 때
"차원 축소"의 관점으로 볼 수도 있습니다.

00:17:28.435 --> 00:17:33.220
CS229를 수강하신 분들이라면
PCA에 대해서 들어본 적 있으실 것입니다.

00:17:33.220 --> 00:17:39.841
PCA는 4096-dim 과 같은 고차원 특징벡터들을
2-dim 으로 압축시키는 기법입니다.

00:17:39.841 --> 00:17:43.183
이 방법을 통해서 특징 공간을 조금 더
직접적으로 시각화시킬 수 있습니다.

00:17:43.183 --> 00:17:51.321
Principle Component Analysis(PCA) 로 이런
일을 할 수는 있지만 t-SNE라는 알고리즘이 더 파워풀합니다.

00:17:51.321 --> 00:17:54.656
t-SNE는  t-distributed stochastic neighbor
embeddings 이라는 뜻입니다.

00:17:54.656 --> 00:18:03.137
많은 사람들이 특징공간을 시각화하기 위해서 사용하는
PCA보다는 조금 더 강력한 방법입니다.

00:18:03.137 --> 00:18:07.264
여기 t-SNE의 예시가 있습니다.

00:18:07.264 --> 00:18:13.231
MNIST를 t-SNE dimensionality reduction
를 통해 시각화한 모습입니다.

00:18:13.231 --> 00:18:17.521
MNIST는 0부터 9까지로 이루어진
손글씨 숫자 데이터셋입니다.

00:18:17.521 --> 00:18:22.226
MNIST의 각 이미지는 Gray scale 28x28 이미지입니다.

00:18:22.226 --> 00:18:32.020
여기에서는 t-SNE가 MNST의 28x28-dim 데이터를 입력으로
받습니다(raw pixels). 그리고 2-dim으로 압축합니다.

00:18:32.020 --> 00:18:37.096
그리고 압축된 2-dim 을 이용해서
MNIST를 시각화합니다.

00:18:37.096 --> 00:18:42.653
t-SNE로 MNIST를 시각화해보면
이런 식으로 자연스럽게 군집화된 모습을 볼 수 있습니다.

00:18:42.653 --> 00:18:47.532
각 군집이 MNIST의 각 숫자를 의미합니다.

00:18:47.532 --> 00:18:57.348
이런 식의 시각화 기법을 ImageNet을 분류하려고
학습시킨 네트워크의 마지막 레이어에도 적용해볼 수 있습니다.

00:18:57.348 --> 00:19:05.073
조금 더 자세히 말씀드리자면 엄청나게 많은 이미지들을
네트워크에 통과시킵니다.

00:19:05.073 --> 00:19:10.865
그리고 각 이미지에 대해서
최종 단의 4096-dim 특징 벡터들을 기록합니다.

00:19:10.865 --> 00:19:14.756
그러면 4096-dim 특징 벡터들을 아주 많이 모을 수 있을 것입니다.

00:19:14.756 --> 00:19:24.277
그리고 이 특징벡터들에 t-SNE을 적용하면
4096-dim에서 2-dim으로 압축됩니다.

00:19:24.277 --> 00:19:36.415
이를 통해 2-dim 특징 공간의 각 grid에
압축된 2-dum 특징들이 시각화시킵니다.

00:19:36.415 --> 00:19:43.417
이를 통해 학습된 특징 공간의 기학적인 모습을
 어렴풋이 추측해 볼 수 있습니다.

00:19:43.417 --> 00:19:48.620
슬라이드의 이미지가 잘 안보이실 것입니다. 온라인에서
고해상도로 다시한번 살펴보시기 바랍니다.

00:19:48.620 --> 00:19:56.451
한번 살펴보자면 좌하단의 초록초록한 군집을 볼 수 있습니다.
이 곳에는 다양한 종류의 꽃들이 있습니다.

00:19:56.451 --> 00:20:01.800
또 다른 곳들에는 다양한 종류의 개들이 모여있고,
다양한 동물들끼리 모여있고, 다양한 지역들이 모여있습니다.

00:20:01.800 --> 00:20:06.192
이를 통해 우리가 학습시킨 특징 공간에는 일종의
불연속적인 의미론적 개념(semantic notion)이 존재하며

00:20:06.192 --> 00:20:11.597
t-SNE을 통한 dimensionality reduction version의
특징 공간을 살펴보며 그 공간을 조금이나마 느낄 수 있습니다.

00:20:11.597 --> 00:20:12.604
질문 있나요?

00:20:23.716 --> 00:20:29.793
한 이미지당 서로 다른 세 가지 정보가 존재합니다.

00:20:29.793 --> 00:20:31.308
1:  우선 (픽셀로 된) 원본 이미지가 있습니다.

00:20:31.308 --> 00:20:33.353
2: 그리고 4096-dim 벡터가 있습니다.
(fc-layer의 출력)

00:20:33.353 --> 00:20:38.109
3: 그리고 t-SNE를 이용해 4096-dim 벡터를
2-dim 벡터로 변환시킨 값이 있습니다.

00:20:38.109 --> 00:20:49.547
결국 원본 이미지를 CNN으로 4096-dim으로 줄이고
이를 다시 t-SNE로 2-dim으로 줄였다고 보시면 되겠습니다.

00:20:49.547 --> 00:20:50.348
질문 있나요?

00:20:55.864 --> 00:20:59.255
질문은 t-SNE로 만든 이 2차원 공간에서 대강
얼마나 많은 데이터들을 표현할 수 있는지 입니다.

00:20:59.255 --> 00:21:06.080
정확히 얼마나 표현할 수 있는지 확신하긴 어렵습니다. t-SNE는
비선형 차원축소 기법이라 상당히 복잡한 성격을 지닙니다.

00:21:06.080 --> 00:21:10.259
다시 한번 확인해 봐야 겠지만
정확히 얼마나 표현할 수 있을지 잘 모르겠습니다.

00:21:10.259 --> 00:21:14.377
질문 있나요?

00:21:14.377 --> 00:21:17.038
질문은 "FC-layer가 아닌 더 상위 레이어에서도
이와 같은 시각화가 가능한지" 입니다.

00:21:17.038 --> 00:21:21.384
네 가능합니다. 하지만 안타깝게도
우리 강의자료에는 없네요. 죄송합니다.

00:21:21.384 --> 00:21:24.603
질문있나요?

00:21:35.559 --> 00:21:39.482
질문은 "이미지들이 차원축소 과정에서
이미지들이 서로 겹치지는 않은지" 입니다.

00:21:39.482 --> 00:21:40.902
네 물론 겹칠 수 있습니다.

00:21:40.902 --> 00:21:47.537
regular grid를 기준으로 nearest neighbor, 즉
각 grid point에 가장 가까운 이미지를 뽑아냅니다.

00:21:47.537 --> 00:21:54.792
따라서 이 시각화 기법이 특징 공간 분포의
모양을 보여주는 것은 아닙니다.

00:21:54.792 --> 00:22:03.122
t-SNE는 분포 자체를 보고자 함은 아닙니다.
그러한 특성을 다루는 몇 가지 다른 시각화 기법들이 존재합니다.

00:22:03.122 --> 00:22:07.713
네트워크의 중간에서 뽑은 특징들을 가지고
해볼 수 있는 다른 것들도 한번 살펴보겠습니다.

00:22:07.713 --> 00:22:13.856
앞서, 중간 레이어에 있는 가중치를 시각화한다고 해도
이를 해석하기는 쉽지 않다고 말씀드렸습니다.

00:22:13.856 --> 00:22:20.846
하지만 중간 레이어의 가중치가 아니라 Activation map을 시각화
해보면 일부 해석할 수 있는 것들을 볼 수 있습니다.

00:22:20.846 --> 00:22:28.603
다시 AlexNet의 예시를 살펴보겠습니다.

00:22:28.603 --> 00:22:35.668
AlexNet의 conv5의 특징은
128 x 13 x 13-dim tensor입니다.

00:22:35.668 --> 00:22:42.386
이 tensor는 128개의 13x13 2-dim gird로 볼 수 있습니다.

00:22:42.386 --> 00:22:49.741
따라서 이 13 x 13 ( x 1) 특징 맵을
그레이스케일 이미지로 시각화해 볼 수 있습니다.

00:22:49.741 --> 00:22:58.501
이를 시각화해보면 conv layer가 입력에서
어떤 특징을 찾고있는지를 짐작해볼 수 있습니다.

00:22:58.501 --> 00:23:03.306
지금 보시고있는 툴은 Jason Yasenski가 만든
아주 멋진 툴로 여러분도 다운로드받으실 수 있습니다.

00:23:03.306 --> 00:23:06.598
지금 동영상으로는 보여드리지 않겠지만
이 분의 웹사이트에 접속하시면 보실 수 있습니다.

00:23:06.598 --> 00:23:10.059
여기에서는 웹캠으로 받은 영상을
CNN에 통과시킵니다.

00:23:10.059 --> 00:23:17.279
그리고 실시간으로 중간의 각 특징 맵들을 시각화시켜서
각 레이어들이 무엇을 찾고있는지를 짐작해볼 수 있습니다.

00:23:17.279 --> 00:23:23.931
이 예시의 입력 이미지는 카메라 앞에 사람이 있는 영상입니다.

00:23:23.931 --> 00:23:28.192
중간 특징들의 대부분은 noisy하고 볼만한 게 없지만

00:23:28.192 --> 00:23:34.277
제가 초록색으로 표시한 특징맵을 보시면,
(왼쪽에 더 크게 확대된 이미지도 있습니다.)

00:23:34.277 --> 00:23:41.103
이 특징맵은 사람의 얼굴에 활성화되는 것 같아 보입니다.
아주 재미있습니다.

00:23:41.103 --> 00:23:51.045
이 특징맵을 통해서, 분명 네트워크의 어떤 레이어에서는
사람의 얼굴을 찾고있는지 모른다는 것을 알 수 있습니다.

00:23:51.045 --> 00:23:54.132
아주 놀라운 발견입니다.

00:23:54.132 --> 00:23:55.517
질문있나요?

00:23:59.038 --> 00:24:04.957
질문은 "완전 새까만 특징 맵들"은
"Dead ReLU" 인지 입니다. 용어에 주의해야 합니다.

00:24:04.957 --> 00:24:09.539
대게 "Dead ReLU"라고 함은 모든 학습 데이터셋에
대해서 "Dead(활성화 되지 않음)" 을 의미합니다.

00:24:09.539 --> 00:24:14.701
이 예시의 경우에는 "특정 입력" 에 대해서
활성화되지 않았을 뿐입니다.

00:24:14.701 --> 00:24:15.702
질문있나요?

00:24:19.457 --> 00:24:22.538
질문은 "만약 ImageNet에 사람의 얼굴이 없다면
어떻게 네트워크가 사람의 얼굴을 인식할 수 있는지" 입니다.

00:24:22.538 --> 00:24:24.182
ImageNet의 사람은 아주 많이 등장합니다.

00:24:24.182 --> 00:24:29.020
물론 ImageNet Classification Chanllenge에의
1000개의 카테고리에 "사람"은 없습니다.

00:24:29.020 --> 00:24:34.906
많은 이미지들에 사람이 등잘하며, 다른 카테고리를 분류하더라도
사람이 등장한다는 특성은 유용한 신호일 수 있습니다.

00:24:34.906 --> 00:24:41.617
그리고 이는 정말 대단한 결과입니다. 분류 문제를 풀기에
유용한 특징들을 알아서 학습한 것이기 떄문입니다.

00:24:41.617 --> 00:24:47.483
가령 고양이만 분류하라고 했을 뿐인데, 고양이를 분류할 때
사람이 유용한 특징이라면 알아서 학습하는 것입니다. 대단한 것이죠.

00:24:50.346 --> 00:24:51.929
질문있나요?

00:24:55.192 --> 00:25:03.334
네트워크의 입력은 3 x 224 x 224 입니다.
그리고 여러 레이어를 통과할 것입니다.

00:25:03.334 --> 00:25:07.731
각 레이어는 3차원의 값을 반환합니다.
(width x height x depth)

00:25:07.731 --> 00:25:10.476
이 3차원 덩어리(chunk)가 바로 네트워크
레이어가 출력하는 값입니다.

00:25:10.476 --> 00:25:18.155
그리고 이 3차원 덩어리를
"activation volume" 이라고 합니다.

00:25:18.155 --> 00:25:22.156
그리고 이 덩어리를 하나씩 잘라내면(slice)
그것이 바로 activation map 입니다.

00:25:34.426 --> 00:25:38.513
앞어 질문은 "입력 이미지가 K x K 라면
activation map이 K x K 인지" 였습니다.

00:25:38.513 --> 00:25:42.489
그렇지 않습니다. 네트워크 중간에 pooling 과 같은
sub sampling 과정이 있을 수 있기 때문입니다.

00:25:42.489 --> 00:25:47.756
하지만 일반적으로 activation map의 크기는
입력 이미지와 선형적인 관계를 갖습니다.

00:25:50.492 --> 00:25:55.625
자 그래서 중간 특징들을 시각화시킬 수 있는
또 다른 방법이 있습니다.

00:25:55.625 --> 00:26:03.453
어떤 이미지가 들어와야 각 뉴런들의 활성이
최대화되는지를 시각화해보는 방법입니다.

00:26:03.453 --> 00:26:08.605
이 예시에서도 다시 한번 AlexNet의
conv5 layer를 사용하겠습니다.

00:26:08.605 --> 00:26:10.926
이 활성화 볼륨 각각을 기억하십시오.

00:26:10.926 --> 00:26:15.738
AlexNet의 conv5는 128 x 13 x 13 한 덩어리의
activation volume을 갖습니다.

00:26:15.738 --> 00:26:19.644
우리는 이제 128개의 채널 중에 하나를 뽑을 것입니다.
여기에서는 17번째 채널을 선택했군요

00:26:19.644 --> 00:26:23.749
그리고 많은 이미지들을 CNN에 통과시킵니다.

00:26:23.749 --> 00:26:27.456
그리고 각 이미지의 conv5 features를 기록해 놓습니다.

00:26:27.456 --> 00:26:37.925
그리고나서 어떤 이미지가 17번째 특징 맵을
최대로 활성화시키는지를 살펴봅니다.

00:26:37.925 --> 00:26:45.161
그리고 현재 이 뉴런은 convolutional layer 입니다.
따라서 receptive field가 작은 편이죠

00:26:45.161 --> 00:26:49.239
각 뉴런이 전체 이미지를 보고있지는 않습니다.
이미지의 일부만을 보고있죠

00:26:49.239 --> 00:27:00.731
따라서 특정 레이어의 특징을 최대화시키는
이미지의 일부분(pathes)을 시각화시킬 것입니다.

00:27:00.731 --> 00:27:06.177
그리고 특정 레이어의 활성화 정도를 기준으로
패치들을 정렬시키면 되겠습니다.

00:27:06.177 --> 00:27:12.575
자 여기 오른쪽에 예시가 있습니다. 이 네트워크의 이름은
"fully.." 사실 어떤 네트워크인지는 크게 중요하진 않습니다.

00:27:12.575 --> 00:27:16.380
어쨌든 여기에 지금 보이는 패치들이 바로
해당 레이어의 활성을 최대화시키는 패치들입니다.

00:27:16.380 --> 00:27:22.500
각 행에 있는 패치들이 하나의 뉴런에서 나온 것입니다.

00:27:22.500 --> 00:27:28.280
각 패치들은 데이터셋에서 나온
패치들을 정렬한 값들이고

00:27:28.280 --> 00:27:30.611
이 패치들이 해당 뉴런의 활성을 최대화시키는 패치들입니다.

00:27:30.611 --> 00:27:35.698
패치의 특징을 통해서 해당 뉴런이
무엇을 찾고있는지 짐작해 볼 수 있습니다.

00:27:35.698 --> 00:27:39.998
가령 맨 윗 행을 보시면
어떤 동그란 모양을 찾고있다는 것을 알 수 있습니다.

00:27:39.998 --> 00:27:44.621
눈 같은 것들이죠. 눈이 많네요.
그리고 파란색 동그란 패치도 있군요

00:27:44.621 --> 00:27:51.303
이로 미루어, 네트워크 레이어의 어떤 뉴런은 입력 영상에서
어떤 푸르스름하고 둥근 물체를 찾고있는 것 같습니다.

00:27:51.303 --> 00:27:56.200
그리고 여기 중간에 보시면 뉴런이 다양한 색상의
문자를 찾는 뉴런도 있습니다.

00:27:56.200 --> 00:28:02.201
또는 다양한 colors &amp; orientations을 가진
휘어진 엣지를 찾는 뉴런이 있다는 것도 알 수 있습니다.

00:28:06.246 --> 00:28:09.199
제가 여기에서 용어를 조금 느슨하게 사용한 감이 있습니다.

00:28:09.199 --> 00:28:13.970
한 뉴런은 conv5 activation map의
하나의 scaler 값을 의미합니다.

00:28:13.970 --> 00:28:19.283
conv5 는 convolutional layer 이기 때문에
한 채널안의 모든 뉴런들은 모두 같은 가중치를 공유합니다.

00:28:19.283 --> 00:28:26.451
각 채널 당 하나의 conv filter가 있고 이에 상응하는
많은 뉴런들이 있습니다.(activation map)

00:28:26.451 --> 00:28:32.532
Convolution의 특성 상 우리는 앞서 보여드린 patch들을
이미지의 모든 곳에서 추출해 낼 수 있습니다.

00:28:32.532 --> 00:28:38.721
그리고 밑의 예시들은 동일 네트워크의 더 깊은 레이어에서
뉴런들을 최대로 활성화시키는 패치들입니다.

00:28:38.721 --> 00:28:42.294
이들은 더 깊은 레이어로부터 왔기 때문에
Receptive field가 훨씬 더 넓습니다.

00:28:42.294 --> 00:28:44.851
이들은 입력 영상에서 훨씬 더 큰
patch들을 기준으로 찾고 있습니다.

00:28:44.851 --> 00:28:49.213
실제로 예시들을 살펴보면 입력 이미지에서
더 큰 구조들(structures)을 찾고있음을 알 수 있습니다.

00:28:49.213 --> 00:28:56.445
두 번째 행을 살펴보면 이는 사람, 또는 사람의 얼굴을
찾고 있는것 같아 보입니다.

00:28:56.445 --> 00:29:06.410
세 번째 행은 카메라의 일부분을 찾고 있는듯 합니다.
이처럼 조금 더 큰 것들을 찾고 있는 것입니다.

00:29:06.410 --> 00:29:11.885
그리고 우리는 조금 더 재밌는 실험을 해볼 수 있습니다.
이는 Zeiler and Fergus가 ECCV'14에 발표한 논문입니다.

00:29:11.885 --> 00:29:14.062
이 논문은 "occlusion experiment"
에 관한 논문입니다.

00:29:14.062 --> 00:29:21.659
이 실험에서 알고자하는 것은 입력의 어떤 부분이
분류를 결정짓는 근거가 되는지에 관한 실험입니다.

00:29:21.659 --> 00:29:25.339
우선 입력 이미지를 받습니다.
가령 이 예시의 경우는 코끼리입니다.

00:29:25.339 --> 00:29:32.486
그리고 이미지의 일부를 가립니다. 그리고 가린 부분을
데이터셋의 평균 값으로 채워버립니다.

00:29:32.486 --> 00:29:39.583
그리고 가려진 이미지를 네트워크에 통과시키고
네트워크가 이 이미지를 예측한 확률을 기록합니다.

00:29:39.583 --> 00:29:44.752
그리고 이 가림 패치( occluded patch)를 전체 이미지에
대해 돌아가면서(slide) 같은 과정을 반복합니다.

00:29:44.752 --> 00:29:53.699
오른쪽의 히트맵은 이미지를 가린 patch의 위치에 따른
네트워크의 예측 확률의 변화를 의미합니다.

00:29:53.699 --> 00:29:59.952
이 실험의 아이디어는, 만약 이미지의 일부를 가렸는데
네트워크의 스코어의 변화가 크게 발생한다면

00:29:59.952 --> 00:30:04.809
가려진 바로 그 부분이 분류를 결정짓는데
아주 중요한 부분이었다는 사실을 짐작할 수 있는 것입니다.

00:30:04.809 --> 00:30:11.420
여기에 "occlusion experiment"을 수행한
세 가지 예시가 있습니다.

00:30:11.420 --> 00:30:14.456
가장 밑의 Go-kart의 예시를 살펴봅시다.

00:30:14.456 --> 00:30:23.077
빨간색 지역은 확률 값이 낮고,
노란색 지역은 확률 값이 높음을 의미합니다.

00:30:23.077 --> 00:30:30.348
앞쪽의 Go-kard를 가렸을 때 Go-kart에 대한 확률이
아주 많이 감소함을 볼 수 있습니다.

00:30:30.348 --> 00:30:38.419
이를 통해 네트워크가 분류를 결정할 때 실제로
go-kart를 아주 많이 고려한다는 사실을 알 수 있습니다.

00:30:38.419 --> 00:30:39.589
질문 있나요?

00:30:47.473 --> 00:30:49.780
질문은 "배경의 경우는 어떻게 된 것인지" 입니다.
(go-kart 이미지의 배경을 가려도 확률이 감소)

00:30:49.780 --> 00:30:56.020
현재 이미지가 너무 작아서 잘 안보이실 수도 있습니다만
뒷쪽 배경에 Go-kart 트랙과 다른 Go-kart들이 있습니다.

00:30:56.020 --> 00:31:00.395
제 생각에는 뒷쪽의 go-kart를 가리는 경우에도
점수에 영향을 미치는 것으로 사료됩니다.

00:31:00.395 --> 00:31:04.628
또는 수평선(horizon)의 영향일지도 모르겠습니다.
Go-kart를 검출하는데 수평선이 유용한 특징일지도 모릅니다.

00:31:04.628 --> 00:31:08.976
사실은 이렇게 해석하기 힘든 경우도 있습니다.
어쨌든 이 방법도 아주 훌륭한 시각화 방법입니다.

00:31:08.976 --> 00:31:10.118
질문 있나요?

00:31:20.486 --> 00:31:23.500
첫 번째 질문이 뭐였죠?

00:31:30.731 --> 00:31:36.802
이 예제의 경우에 이미지 한장에 대해서
현재 이미지의 모든 부분을 조금씩 가려본 것입니다.

00:31:36.802 --> 00:31:38.777
두 번 질문은 "이 시각화 방법이
학습에 어떻게 유용한지" 입니다.

00:31:38.777 --> 00:31:42.982
학습 하는데 직접적으로 유용하지는 않습니다. 여기에서 얻는
정보를 학습 과정에 집어 넣을 수는 없습니다.

00:31:42.982 --> 00:31:49.341
다만 "사람"이 네트워크가 무엇을 하고 있는지를
이해할 수 있는 도구일 뿐입니다.

00:31:49.341 --> 00:31:54.296
결국 이런 시각화는 네트워크의 성능을 높히려는
목적이 아니라 "여러분이 이해" 함이 목적입니다.

00:31:54.296 --> 00:31:57.890
그리고 이와 관련된 또 다른 아이디어가 있습니다.
"Saliency Map" 과 관련된 아이디어입니다.

00:31:57.890 --> 00:32:00.534
여러분이 앞으로 과제에서 보게될 것입니다.

00:32:00.534 --> 00:32:02.578
이 경우에도 같은 질문이 있습니다.

00:32:02.578 --> 00:32:07.831
입력 이미지가 들어옵니다. 이 경우에는 "개" 입니다.
그리고 이 이미지를 "개" 라고 예측했을 떄,

00:32:07.831 --> 00:32:11.796
우리가 알고싶은 것은 네트워크가 픽셀들을
보고서 이미지를 "개" 라고 분류했는지 입니다.

00:32:11.796 --> 00:32:19.452
앞서 특정 픽셀을 가리는(masking) 방법도 있었습니다만
Saliency Maps은 조금 다른 접근법을 취합니다.

00:32:19.452 --> 00:32:25.354
이 방법은 몇해 전 Karen Simonenian의 논문에서 나온
비교적 간단한 방법입니다.

00:32:25.354 --> 00:32:31.694
이 방법은 입력 이미지의 각 픽셀들에 대해서,
예측한 클래스 스코어의 그레디언트를 계산하는 방법입니다.

00:32:31.694 --> 00:32:36.042
이 방법은 일종의 "1차 근사적 방법"으로
어떤 픽셀이 영향력있는지를 알려줍니다.

00:32:36.042 --> 00:32:43.963
입력 이미지의 각 픽셀에 대해서, 우리가 그 픽셀을 조금
바꿨을 때 클래스 스코어가 얼마나 바뀔까요?

00:32:43.963 --> 00:32:50.496
이 질문은 어떤 픽셀이 "개"를 분류하는데 있어서 어떤 픽셀들이
필요한지알 수 있는 또 다른 방법이 될 수 있습니다.

00:32:50.496 --> 00:32:59.356
이 방법을 통해 "개" 이미지의 Saliency map을 만들어보면
"개"의 윤곽이 나타남을 알 수 있습니다.

00:32:59.356 --> 00:33:04.985
이는 네트워크가 이미지에서 어떤 픽셀들을
찾고 있는지를 짐작할 수 있습니다.

00:33:04.985 --> 00:33:11.675
이 방법은 다른 이미지들에도 적용해보면
네트워크가 올바른 지역을 보고있다는 것을 알 수 있습니다.

00:33:11.675 --> 00:33:13.360
좀 위안이 되는 것이죠

00:33:13.360 --> 00:33:14.462
질문 있나요?

00:33:17.407 --> 00:33:21.916
질문은 "사람들이 Saliency Maps을
semantic segmentation에도 사용하는지" 입니다.

00:33:21.916 --> 00:33:26.741
네 맞습니다. (웃음)
여러분들은 정말 최고입니다.

00:33:26.741 --> 00:33:29.513
semantic segmentation은 Karen의 논문에
또 다른 주제로 실려있습니다.

00:33:29.513 --> 00:33:38.925
아이디어, segmentation 레이블 없이 Saliency Maps 만
가지고 semantic segmentation을 수행할 수 있다는 것입니다.

00:33:38.925 --> 00:33:43.908
이들은 Grabcut Segmentation Algorithm을 이용합니다.
Grabcut에 대해서는 더 자세하게 말씀드리지는 않겠습니다.

00:33:43.908 --> 00:33:47.772
Grabcut은 간단히 말해
interactive segmentation algorithm 입니다.

00:33:47.772 --> 00:33:55.697
이 Saliency Map과 Grabcut을 잘 조합하면
이미지 내에서 객체를 Segmentation할 수 있습니다.

00:33:55.697 --> 00:34:00.326
아주 멋진 아이디어입니다.
하지만 그렇게 잘 되지는 않습니다.

00:34:00.326 --> 00:34:07.182
supervision을 가지고 학습을 시키는 네트워크에
비해서는 훨씬 더 안좋습니다.

00:34:07.182 --> 00:34:13.458
실용적인지는 잘 모르겠지만
작동한다는 것 자체가 정말 놀랍습니다.

00:34:13.458 --> 00:34:19.025
supervision으로 segmentation을 학습시킨
모델보다는 훨씬 안좋지만 말이죠

00:34:19.025 --> 00:34:23.791
또 다른 아이디어로는
guided back propagation이 있습니다.

00:34:23.791 --> 00:34:30.001
이번에 할 질문은, 어떤 한 이미지가 있을 떄

00:34:30.001 --> 00:34:37.420
이제는 클래스 스코어가 아니라
네트워크의 중간 뉴런을 하나 고릅니다.

00:34:37.420 --> 00:34:44.199
그리고 입력 이미지의 어떤 부분이, 내가 선택한
중간 뉴런의 값에 영향을 주는지를 찾는 것이죠

00:34:44.199 --> 00:34:49.059
이 경우에도 앞서 했던 방법처럼
Saliency Map을 만들어볼 수 있을 것입니다.

00:34:49.059 --> 00:34:53.466
이 경우에는 이미지의 각 픽셀에 대한
"클래스 스코어"의 그래디언트를 계산하는 것이 아니라

00:34:53.466 --> 00:34:58.815
입력 이미지의 각 픽셀에 대한 네트워크 중간
뉴런의 그레디언트를 계산합니다.

00:34:58.815 --> 00:35:05.832
이를 통해 어떤 픽셀이 해당 뉴런에
영향을 주는 지 알 수 있습니다.

00:35:05.832 --> 00:35:08.342
이 경우에도 평범한 back propagation을 이용합니다.

00:35:08.342 --> 00:35:15.093
하지만 back propagation 과정에서 조금의 트릭을 가미하면
조금 더 깨끗한 이미지를 얻을수 있습니다.

00:35:15.093 --> 00:35:21.393
이를 "guided back propagation" 이라고 합니다.
Zeilerand Fergus의 2014년 논문입니다.

00:35:21.393 --> 00:35:24.203
이번 시간에 이에 대해 더 깊게는 들어가지 않겠지만

00:35:24.203 --> 00:35:30.220
이 방법(guided backprop)은 backprop 시
ReLU를 통과할 때 조금의 변형을 가해줍니다.

00:35:30.220 --> 00:35:37.254
ReLU의 그레디언트의 부호가 양수 이면 그대로 통과시키고
부호가 음수이면 backprop하지 않는 방법입니다.

00:35:37.254 --> 00:35:46.948
이로인해 전체 네트워크가 실제 그레디언트를 이용하는
것이 아니라 "양의 부호인 그레디언트" 만을 고려하게 됩니다.

00:35:46.948 --> 00:35:53.614
이 방법이 왜 좋은지는 해당 논문을 각자
읽어보시기 바랍니다.

00:35:53.614 --> 00:36:01.649
실험 결과를 보면, guided backprop이 그냥에 비해
훨씬 더 선명하고 좋은 이미지를 얻을 수 있음을 알 수 있습니다.

00:36:01.649 --> 00:36:07.223
이 이미지들은 입력 이미지에 어떤 픽셀들이
특정 뉴런에 영향을 미치는지를 알려줍니다.

00:36:07.223 --> 00:36:12.467
앞서 슬라이드에서 "maximally activating patches"
파트에서 이와 비슷한 시각화기법을 살펴봤었습니다.

00:36:16.488 --> 00:36:20.174
"maximally activating patches" 기법 외에도

00:36:20.174 --> 00:36:27.604
"guided backpropagation" 이라는 방법을 통해서
패치의 어떤 부분이 뉴런에 영향을 미치는지 알 수 있습니다.

00:36:27.604 --> 00:36:37.139
맨 상당의 예를 살펴봅시다. 이미지들을 살펴보면
이 뉴런이 아마도 둥그런 것들을 찾고있음을 짐작해볼 수 있습니다.

00:36:37.139 --> 00:36:42.028
guided backprob 결과(왼쪽)를 살펴보면 방금 전 우리가
짐작했던 직관을 어느정도 확신할 수 있습니다.

00:36:42.028 --> 00:36:49.218
실제로 이미지 상의 둥근 부분들이 뉴런의 실제 값에
영향을 미치고 있음을 직접 확인할 수 있기 때문입니다.

00:36:49.218 --> 00:36:56.514
이렇게 guided backprob은 중간 레이어가 무엇을 찾고 있는지를
이해하기 위한 영상을 합성하는데 아주 유용합니다.

00:36:56.514 --> 00:37:05.108
하지만 guided backprob이나 saliency maps을 계산하는
방법들은 고정된 입력 이미지에 대한 연산을 수행할 뿐입니다.

00:37:05.108 --> 00:37:12.882
이 방법들은 "고정된" 입력 이미지, 또는 입력 패치의 어떤 부분이
해당 뉴런에 영향을 미치는지를 말해줍니다.

00:37:12.882 --> 00:37:19.110
그렇다면 입력 이미지에 의존적이지 않은 방법은 없을까요?

00:37:19.110 --> 00:37:24.641
해당 뉴런을 활성화시킬 수 있는
어떤 "일반적인" 입력 이미지가 있을까? 란 질문을 할 수 있습니다.

00:37:24.641 --> 00:37:29.118
이에 대한 질문은 "Gradient ascent" 라는
방법이 해답을 제시해줄 수 있습니다.

00:37:29.118 --> 00:37:34.903
우리는 지금까지 Loss를 최소화시켜 네트워크를
학습시키기 위해 Gradient decent를 사용했습니다.

00:37:34.903 --> 00:37:40.552
하지만 여기에서는 네트워크의
가중치들을 전부 고정시킵니다.

00:37:40.552 --> 00:37:50.932
그리고  Gradient ascent를 통해 중간 뉴런 혹은 클래스
스코어를 최대화 시키는 이미지의 픽셀들을 만들어냅니다.

00:37:50.932 --> 00:37:58.333
Gradient ascent는 네트워크의 가중치를 최적화하는
방법이 아닙니다. 가중치들은 모두 고정되어 있습니다.

00:37:58.333 --> 00:38:07.104
대신 뉴런, 또는 클래스 스코어가 최대화될 수 있도록
입력 이미지의 픽셀 값을 바꿔주는 방법입니다.

00:38:07.104 --> 00:38:10.475
이 방법에는 regularization term이 필요합니다.

00:38:10.475 --> 00:38:19.078
우리는 지금까지 regularization terms의 역할을 가중치들이
학습 데이터로의 과적합을 방지하기 위함으로 배웠습니다.

00:38:19.078 --> 00:38:27.109
이 경우에도 유사합니다. 생성된 이미지가  특정 네트워크의
특성에 완전히 과접합 되는 것을 방지하기 위함입니다.

00:38:27.109 --> 00:38:34.664
regularization term을 추가함으로서, 우리는 생성된 이미지가
두 가지 특성을 따르길 원하는 것입니다.

00:38:34.664 --> 00:38:39.269
하나는 이미지가 특정 뉴런의 값을 최대화시키는
방향으로 생성되길 원하는 것이고

00:38:39.269 --> 00:38:42.111
그리고 다른 하나는 이미지가 자연스러워 보여야 한다는 것입니다.

00:38:42.111 --> 00:38:46.485
생성된 이미지가 자연 영상에서 일반적으로 볼 수 있는
이미지이길(statistics) 원하는 것입니다.

00:38:46.485 --> 00:38:52.936
이런 류의 regularization term의 목적은
생성된 이미지가 비교적 자연스럽도록 강제하는 역할입니다.

00:38:52.936 --> 00:38:57.116
앞으로 다양한 regulaizer들을 살펴보겠습니다.

00:38:57.116 --> 00:39:04.371
Gradient Ascent는 비교적 간단한 방법입니다. 과제 3에서
여러분이 직접 구현해보실 수 있을 것입니다.

00:39:04.371 --> 00:39:10.410
Gradient Ascent를 위해서는 초기 이미지가 필요합니다.
이 이미지는 zeros, uniform, noise 등으로 초기화시켜줍니다.

00:39:10.410 --> 00:39:19.922
초기화를 하고나면 이미지를 네트워크에 통과시키고
여분이 관심있는 뉴런의 스코어를 계산합니다.

00:39:19.922 --> 00:39:26.643
그리고 이미지의 각 픽셀에 대한 해당 뉴런 스코어의
그레디언트를 계산하여 back prop을 수행합니다.

00:39:26.643 --> 00:39:33.897
여기에서는 Gradient Ascent를 이용해서 이미지 픽셀
자체를 업데이트합니다. 해당 스코어를 최대화시키려 하겠죠

00:39:33.897 --> 00:39:38.786
이 과정을 계속 반복하고나면
아주 멋진 이미지가 탄생합니다.

00:39:38.786 --> 00:39:42.311
여기에서도 이미지에 대한 regularizer를 언급하지 않을수 없습니다.

00:39:42.311 --> 00:39:49.428
여기에서는 단순하게 생성된 이미지에 대한
L2 norm을 계산해서 더해줍니다.

00:39:49.428 --> 00:39:51.466
사실 L2 norm을 추가하는 것 자체에 큰 의미가 있는 것은 아닙니다.

00:39:51.466 --> 00:40:01.764
Gradient Ascent와 같은 이미지 생성과 관련된 방법들의
초창기 문헌에서 종종 보이는 regularizer 중 하나일 뿐입니다.

00:40:01.764 --> 00:40:12.153
이 네트워크를 학습시켜보면, 가령 왼쪽 상당의 덤벨의
스코어를 최대화시키는 이미지가 생성됩니다.

00:40:12.153 --> 00:40:14.820
그리고 생성된 이미지를 살펴보면

00:40:14.820 --> 00:40:19.726
잘 안보이실 수도 있지만, 여러 덤벨 모양이 생성되었음을
알 수 있습니다.

00:40:19.726 --> 00:40:23.162
여러 덤벨들이 이곳 저곳에 중첩되어 있는 모양입니다.

00:40:23.162 --> 00:40:29.111
그리고 컵의 생성된 이미지를 보면 아주 다양한 컵들이
충첩되어 있는 이미지를 볼 수 있습니다.

00:40:29.111 --> 00:40:30.466
달마시안의 예가 정말 끝내줍니다.

00:40:30.466 --> 00:40:35.478
달마시안의 특징이라고 할 수 있는 검정/흰색 반점
무늬를 볼 수 있습니다.

00:40:35.478 --> 00:40:40.388
레몬의 경우에는 얼룩 얼룩한 노란색이 보입니다.

00:40:40.388 --> 00:40:43.539
여기 몇 가지 예제가 더 있습니다.
거위의 경우도 정말 놀랍습니다.

00:40:43.539 --> 00:40:46.514
키트 여우(kit fox)도 정말 키트 여우같아 보입니다.

00:40:46.514 --> 00:40:47.454
질문 있나요?

00:40:55.528 --> 00:40:57.929
질문은 "왜 이미지들이 무지개 색인지" 입니다.

00:40:57.929 --> 00:41:02.434
이 시각화 방법을 이용해서 실제 색상을
시각화하려면 상당히 까다롭습니다.

00:41:02.434 --> 00:41:06.693
실제 모든 이미지들은 0에서  255 사이의
값들로 이루어져야 합니다.

00:41:06.693 --> 00:41:10.395
이는 constrained optimization 문제입니다.

00:41:10.395 --> 00:41:15.721
하지만 Gradient ascent와 같은 일반적인 방법들은
제약조건이 없는(unconstrained) 경우입니다.

00:41:15.721 --> 00:41:21.848
따라서 여러분이 Projected gradient descent 와
같은 알고리즘을 사용하고 마지막에 rescale한 경우라면

00:41:21.848 --> 00:41:27.799
시각화 할 때 나타나는 색상과 관련해서는
너무 크게 신경쓸 필요 없습니다.

00:41:27.799 --> 00:41:28.702
질문 있나요?

00:41:32.801 --> 00:41:36.846
질문은 "아무 regularizer도 사용하지 않으면
어떻게 되는지" 입니다.

00:41:36.846 --> 00:41:44.860
그렇게 해도 클래스 스코어를 최대화시키는
어떤 이미지가 생성되기는 할 것입니다.

00:41:44.860 --> 00:41:48.522
하지만 그 이미지는 아무것도 아닌 것 처럼 보일 것입니다.
램덤 노이즈처럼 보일 뿐입니다.

00:41:48.522 --> 00:41:54.538
그렇긴 해도 그 이미지 자체가 가지는 아주 흥미로운
특징이 있습니다. 이는 나중에 더 자세히 배울 것입니다.

00:41:54.538 --> 00:42:00.913
어쩃든 이 이미지를 가지고는 네트워크가 어떤 것들을
찾고 있는지를 이해하기는 힘듭니다.

00:42:00.913 --> 00:42:09.607
따라서 이를 위해서는 regularizer를 추가해서
이미지가 조금 더 자연스럽게 생성되도록 하는 편이 좋습니다.

00:42:09.607 --> 00:42:10.471
질문 있나요?

00:42:34.416 --> 00:42:38.492
질문은 "multimodality를 다루는 다른 방법은 없는지"입니다.
(클래스 내에서도 다양한 mode가 있음.)

00:42:38.492 --> 00:42:44.847
당연히 있습니다. 현재 시각화에 대한 본격적인 이야기는
이제 시작입니다.

00:42:44.847 --> 00:42:51.517
시각화의 다른 접근법들은 regularizer를 더욱
향상시키고 이미지를 더 잘 시각화시키는 방법에 관한 것입니다.

00:42:51.517 --> 00:42:58.621
Jason Yesenski, et al의 논문이 있습니다. 이들은
아주 인상적인 regularizers를 추가했습니다.

00:42:58.621 --> 00:43:00.924
L2 norm constraint은 여전히 있습니다.

00:43:00.924 --> 00:43:06.213
그리고 최적화 과정에 이미지에  주기적으로
가우시안 블러를 적용합니다.

00:43:06.213 --> 00:43:12.441
그리고 주기적으로 값이 작은 픽셀들은 모두 0으로 만듭니다.

00:43:12.441 --> 00:43:14.694
낮은 기울기의 픽셀 값 중 일부는 0으로 설정됩니다.
그레디언트가 작은 값들도 모두 0으로 만듭니다.

00:43:14.694 --> 00:43:17.559
이는 일종의 projected Gradient descent
라고 볼 수 있습니다.

00:43:17.559 --> 00:43:24.555
생성된 이미지를 더 좋은 특성을 가진 이미지 집합으로
주기적으로 매핑시키는 방법입니다. (밑에 세가지 방법으로)

00:43:24.555 --> 00:43:28.241
가령 가우시안 블러와 같은 스무딩 연산을 통해서죠

00:43:28.241 --> 00:43:32.870
이 방법을 이용하면 훨씬 더 보기 좋은 이미지를
생성할 수 있습니다. 훨씬 더 깔끔합니다.

00:43:32.870 --> 00:43:38.553
홍학은 조금 더 홍학처럼 생겼습니다.
딱정벌레도 더 잘 보입니다.

00:43:38.553 --> 00:43:41.695
검은 백조도 검은 백조처럼 잘 보입니다.

00:43:41.695 --> 00:43:48.211
그 중에 당구대가 상당히 인상적입니다.
확실히 당구대의 구조가 선명합니다.

00:43:48.211 --> 00:43:55.209
이처럼 조금 괜찮은 regularizer들을 추가하게 되면
생성되는 이미지가 조금 더 깔끔해질 수 있습니다.

00:43:55.209 --> 00:44:01.038
이 과정은 최종 스코어에만 적용하는게 아니라
중간 뉴런에도 적용해볼 수 있습니다.

00:44:01.038 --> 00:44:10.111
"당구대" 클래스의 스코어를 최대화시키는 것이 아니라
중간의 뉴런을 최대화시키는 이미지를 생성해볼 수도 있습니다.

00:44:10.111 --> 00:44:11.118
질문 있나요?

00:44:16.743 --> 00:44:19.393
질문은 "이 예제의 네가지 이미지가 무엇인지" 입니다.

00:44:19.393 --> 00:44:21.794
우선 이 이미지는 처음에 램덤 초기화된 이미지입니다.

00:44:21.794 --> 00:44:25.681
따라서 이 네 개의 이미지들은 서로 다르게
램덤으로 초기화된 입력 이미지입니다.

00:44:28.106 --> 00:44:36.113
다시 수업으로 돌아가서, 앞서 클래스 스코어에 적용했던 과정은
네트워크의 중간 뉴런을 최대화시키는 과정에 동일하게 적용됩니다.

00:44:36.113 --> 00:44:40.174
이를 통해서 중간 뉴런이 무엇을 찾고있는지
짐작해볼 수 있습니다.

00:44:40.174 --> 00:44:44.605
가령 네번째 레이어의 경우에는 나선형의 무언가를
찾고있는 것 같습니다.

00:44:44.605 --> 00:44:49.703
또 어떤 뉴런은 애벌레를 찾는 것 같아 보입니다.
정확이 무엇인지는 구별하기 힘들군요

00:44:49.703 --> 00:44:56.585
여기 예제 이미지가 큰 이미지일수록 receptive
fileds 가 더 큰 뉴런들입니다.

00:44:56.585 --> 00:44:58.664
Receptive field가 클수록
이미지 패치 내에 더 큰 곳을 볼 수 있습니다.

00:44:58.664 --> 00:45:03.549
이런 뉴런들은 입력 이미지에서 더 큰 구조와
더 복잡한 패턴을 찾는 경향이 있습니다.

00:45:03.549 --> 00:45:04.802
아주 멋집니다.

00:45:07.499 --> 00:45:15.559
사람들이 이 시각화 방법이 이미지의 특징들을
잘 살리는 것에 아주 열광했습니다.

00:45:15.559 --> 00:45:23.697
방금 전 누군가가 질문해주신 multimodality 를
이 논문에서 아주 잘 다루고 있습니다.

00:45:23.697 --> 00:45:29.849
이 논문에서는 최적화 과정 속에 multimodality를
아주 명시적으로 다루고 있습니다.

00:45:29.849 --> 00:45:35.254
각 클래스마다 클러스터링 알고리즘을 수행합니다.

00:45:35.254 --> 00:45:42.667
한 클래스 내 서로 다른 모드들 끼리 다시 한번 클래스가 나뉩니다.
그리고 나뉜 모드들과 가까운 곳으로 초기화를 해주는 것이죠

00:45:42.667 --> 00:45:45.890
이 방법을 통해서 multimodality를 다룰 수 있는 것입니다.

00:45:45.890 --> 00:45:51.675
직관적으로 보면, 가령 여기 있는 여덟개의 이미지는
모두 식료품점(grocery store) 입니다.

00:45:51.675 --> 00:45:56.401
가장 상위의 이미지들은 선반 위에 전시된
물건들을 클로즈업 한 것 같아 보입니다.

00:45:56.401 --> 00:45:59.068
이들의 레이블은 "식료품 점" 입니다.

00:45:59.068 --> 00:46:04.221
그리고 하단의 이미지들은 사람들이 식료품점을
돌아다니고 있는 모슴인 것 같습니다.

00:46:04.221 --> 00:46:06.085
이 또한 식료품점으로 레이블링됩니다.

00:46:06.085 --> 00:46:08.073
하지만 이 둘은 아주 다르게 생겼습니다.

00:46:08.073 --> 00:46:10.988
많은 클래스들이 이렇게 multimodality를 가지고 있습니다.

00:46:10.988 --> 00:46:17.648
이미지를 생성할 때 이런 식으로  multimodality를
명시하게 되면 아주 좋은 (다양한) 결과를 얻을 수 있게 됩니다.

00:46:17.648 --> 00:46:22.569
예제를 조금 더 살펴보도록 하죠. 여러 클래스의
이미지를 합성해 보았습니다.

00:46:22.569 --> 00:46:31.840
피망, 카르둔, 딸기, 잭오랜턴 등을 볼 수 있습니다.
이미지가 아주 잘 생성되었습니다.

00:46:31.840 --> 00:46:38.177
다음 장은 깊게 들어가지는 않겠습니다만
이 방법은 훨씬 더 놀라운 방법입니다.

00:46:38.177 --> 00:46:43.623
이 방법은 이미지를 이쁘게 생성해 내기 위해서
훨씬 더 강력한 사전 정보(prior)를 이용합니다.

00:46:43.623 --> 00:46:48.921
여기 보이는 이미지들이 모두 ImageNet의 특정
클래스를 최대화하는 이미지를 생성해 낸 것입니다.

00:46:48.921 --> 00:46:59.020
기본 아이디어는 입력 이미지의 픽셀을 곧장 최적화하는 것
대신에 FC6를 최적화하는 것입니다.

00:46:59.020 --> 00:47:03.342
이를 위해서는 feature inversion network 등을 사용해야
하지만  자세히 들어가진 않겠습니다.

00:47:03.342 --> 00:47:05.290
관심있으신 분들은 논문을 읽어보시기 바랍니다.
아주 놀라운 방법입니다.

00:47:05.290 --> 00:47:11.905
요점은 이런 이미지 생성 문제에서
사전 지식(priors)를 추가하게 된다면

00:47:11.905 --> 00:47:16.662
아주 리얼한 이미지를 만들어낼 수 있다는 것입니다.

00:47:18.951 --> 00:47:23.839
이 방법도 여러분들이 시도해볼만한
아주 좋은 방법이 될 수 있습니다. 어쨋건,

00:47:23.839 --> 00:47:29.893
이미지 픽셀의 그레디언트를 이용해서 이렇게
이미지를 합성하는 방법은 아주 강력합니다.

00:47:29.893 --> 00:47:34.288
이를 통해 시도해볼 수 있는 아주 재미있는 것은 바로
네트워크를 속이는 이미지(fooling image)를 만드는 것입니다.

00:47:34.288 --> 00:47:43.362
우선 아무 이미지나 하나 고릅니다.
가령 코끼리 이미지를 골랐다고 해봅시다.

00:47:43.362 --> 00:47:49.418
그리고 네트워크가 이 이미지는 코알라 라고
분류하도록 이미지를 조금씩 바꿉니다.

00:47:49.418 --> 00:47:57.064
이렇게 코끼리 이미지를 조금씩 바꾸다보면
네트워크는 이 이미지를 코알라라고 분류해 버립니다.

00:47:57.064 --> 00:48:05.931
여러분이 혹시라도 코끼리가 갑자기 귀여운 귀를
가진 코알라로 변신하는 모습을 상상할 지 모르곘습니다만

00:48:05.931 --> 00:48:09.241
사실은 그런 일은 일어나지 않습니다.
이점이 아주 놀라운 점입니다.

00:48:09.241 --> 00:48:17.377
코끼리 사진을 가지고 코알라로 분류하도록
이미지를 바꿔보면

00:48:17.377 --> 00:48:24.853
실제로는 두 번째 이미지 처럼 보입니다. 네트워크는 두 번째
이미지를 코알라로 분류합니다. 우리에게는 별반 차이가 없습니다.

00:48:24.853 --> 00:48:28.016
아주 수상하기도(fishy) 하면서
놀랍기도 합니다.

00:48:28.016 --> 00:48:34.114
밑에 예제가 하나 더있습니다. 배 인것 같은데
ImageNet 클래스로는 Schooner(범선) 입니다.

00:48:34.114 --> 00:48:37.170
이제 네트워크가 아이팟으로 분류하도록 합니다.

00:48:37.170 --> 00:48:41.881
두 번째 이미지를 보면 우리에게는 똑같이 배인데
네트워크는 아이팟이라고 인식하고 있습니다.

00:48:41.881 --> 00:48:46.260
두 이미지 사이의 픽셀 값의 차이는 거의 없습니다.

00:48:46.260 --> 00:48:52.025
우리는 픽셀 값의 차이에서 코알라나 아이팟의
특징이라고는 찾아볼 수 없습니다.

00:48:52.025 --> 00:48:58.924
그저 랜덤한 패턴의 노이즈로 보일 뿐입니다. 그렇다면 질문은
"무슨 일이 일어난 것일까요?", "어떻게 이런게 가능한 것일까요?"

00:48:58.924 --> 00:49:03.635
굿조만한 우리 수업 게스트로
Ian Goodfellow를 초청할 예정입니다.

00:49:03.635 --> 00:49:08.068
Ian Goodfellow가 와서 이와관련한 현상을
조금 더 자세히 설명해 줄 것입니다. 아주 재밌을 것입니다.

00:49:08.068 --> 00:49:11.006
하지만 여기에서는 더 이상 언급하지 않겠습니다.
왜냐하면 여러분들의 과제이기 떄문이죠

00:49:11.006 --> 00:49:11.595
질문 있나요?

00:49:16.320 --> 00:49:20.050
질문은 "학습 데이터로도 네트워크를 속일 수 있는지" 입니다.

00:49:20.050 --> 00:49:27.214
이와 관련된 모든 것들은 Ian이 와서 소개해줄 것입니다.
Ian Goodfellow가 와서 강연 내내 다룰 것입니다.

00:49:27.214 --> 00:49:28.885
질문 있나요?

00:50:00.608 --> 00:50:03.478
질문은 "왜 우리가 이딴거(stuff)에 관심을 가져야 하는 것인지"

00:50:03.478 --> 00:50:08.685
제가 질문을 조금 거칠게 표현했습니다. 죄송합니다.

00:50:24.573 --> 00:50:32.027
질문은 "중간 뉴런을 이해하는 것이 어떻게 최종 클래스
분류를 이해하는데 도움을 줄 수 있는지" 입니다.

00:50:32.027 --> 00:50:38.921
사실 이런 식으로 중간 레이어를 시각화하는 방법들은
딥러닝의 비판에 대한 반응에서 유래합니다.

00:50:38.921 --> 00:50:43.011
딥러닝의 비판이라 함은
"딥러닝 이라는 블랙박스를 가진건 알겠어,

00:50:43.011 --> 00:50:47.350
- 그리고 그걸 그레디언트로 잘 학습시켜서 좋은 결과가
나오는건 알겠는데, 사실 결과를 믿진 못하겠어

00:50:47.350 --> 00:50:51.272
딥러닝의 결과가 어떻게 나왔는지를
당신조차 이해할수 없잖아?" 와 같은 질문이죠

00:50:51.272 --> 00:51:01.530
이런 많은 시각화 기법들은 왜 딥러닝이 분류 문제를
더 잘 푸는지를 사람들이 이해하기 위해 고안되었습니다.

00:51:01.530 --> 00:51:07.721
가령, 딥러닝이 아닌 다른 기계학습 기법들을 생각해보면

00:51:07.722 --> 00:51:10.493
가령 선형 모델의 경우가 일반적으로 해석하기 훨씬 더 수월합니다.

00:51:10.493 --> 00:51:17.457
각 가중치를 보고 입력 특징들 중 어떤 부분이 얼마나 모델이
결정을 내리는데 영향을 미치는지 해석하기 용이합니다.

00:51:17.458 --> 00:51:19.459
Random forest와 같은 dectision tree를 보면 말이죠.

00:51:19.459 --> 00:51:27.442
이런 기계학습 기법들이 블랙박스인 CNN보다는
훨씬 더 자연스럽고 해석하기도 쉽습니다.

00:51:27.442 --> 00:51:33.520
딥러닝에 대한 앞서 언급한 비판들에 대한 대안으로
시각화 기법들이 등장했습니다. "그래 모델이 복잡하긴 하지,

00:51:33.520 --> 00:51:37.263
하지만 들춰보면 해석 가능한 것들이 있다구!"
라고 말하는 것입니다.

00:51:37.263 --> 00:51:42.201
딥러닝 모델이 아무렇게나 분류하는 것이 아니라
의미있는 행동을 하고 있음을 증명하려는 것입니다.

00:51:44.891 --> 00:51:50.989
이미지에 그레디언트를 업데이트하는 방식으로 가능한
재미있는 아이디어가 하나 더 있습니다. "DeepDeram" 입니다.

00:51:50.989 --> 00:51:55.592
작년 Google에서 나온 아주 재미있는
블로그 포스팅이 있었습니다.

00:51:55.592 --> 00:52:00.859
DeepDream의 "과학적 가치"의 측면에서 보자면
그저 "재미" 만을 위한 것입니다.

00:52:00.859 --> 00:52:04.284
DeepDream의 목적은
"재미있는 이미지를 만드는 것" 입니다.

00:52:04.284 --> 00:52:10.186
부가적으로 모델이 이미지의 어떤 특징들을
찾고 있는지를 짐작할 수도 있습니다.

00:52:10.186 --> 00:52:15.275
DeepDeram에서는 입력 이미지를 CNN의
중간 레이어를 어느정도 통과시킵니다.

00:52:15.275 --> 00:52:17.035
그리고 back prop을 할 차례입니다.

00:52:17.035 --> 00:52:20.742
해당 레이어의 그레디언트를
activation 값으로 설정합니다.

00:52:20.742 --> 00:52:25.427
그리고 back prob을 하여 이미지를 업데이트합니다.
이 과정을 계속 반복합니다.

00:52:25.427 --> 00:52:31.682
네트워크에 의해 검출된 해당 이미지의 특징들을
증폭시키려는 것으로 해석할 수 있습니다.

00:52:31.682 --> 00:52:35.875
해당 레이어에 어떤 특징들이 있던지
그 특징들을 그레디언트로 설정하면

00:52:35.875 --> 00:52:40.010
이는 네트워크가 이미지에서 이미 뽑아낸 특징들을
더욱 증폭시키는 역학을 하는 것입니다.

00:52:40.010 --> 00:52:46.918
그리고 이는 해당 레이어에서 나온 특징들의
L2 norm을 최대화시키는 것으로 볼 수 있습니다.

00:52:46.918 --> 00:52:55.999
DeepDream의 코드는 아주 심플합니다.
이는 여러분의 과제에 포함되어 있습니다.

00:52:55.999 --> 00:53:00.785
여러분이 앞으로 과제를 통해 접하겠지만
여기에는 몇 가지 트릭이 존재합니다.

00:53:00.785 --> 00:53:04.443
트릭 중 하나는 그레이언트를 계산하기에 앞서
이미지를 조금씩 움직이는 것입니다.(jitter)

00:53:04.443 --> 00:53:11.187
원본 이미지를 그대로 네트워크에 통과시키는 것 대신에
이미지를 두 픽셀 정도 이동시킵니다.

00:53:11.187 --> 00:53:19.540
이는 regularizer 역할을 해서 자연스럽고
부드러운 이미지를 만들어줍니다.

00:53:19.540 --> 00:53:26.653
그리고 여기에 L1 Normalization도 들어갑니다.
이는 이미지 합성 문제에서 아주 유용한 트릭입니다.

00:53:26.653 --> 00:53:33.843
그리고 픽셀 값을 한번 클리핑(Clipping) 해주기도 합니다.
이미지라면 값이 0-255 사이에 있어야만 합니다.

00:53:33.843 --> 00:53:39.335
이는 일종의 projected gradient decent인데  실제
이미지가 존재할 수 있는 공간으로 매핑시키는 방법입니다.

00:53:39.335 --> 00:53:46.215
이렇게 하늘 이미지를 가지고 알고리즘을 수행시키면
이처럼 아주 재미있는 결과를 보실 수 있습니다.

00:53:46.215 --> 00:53:52.614
하늘에 조그만한 특징들이 보이실 것입니다.
이들을 앞선 과정을 통해 증폭된 것들입니다.

00:53:52.614 --> 00:53:59.007
돌연변이 동물같은 것들이 나타났습니다.
나선 모양의 것들도 나타났습니다.

00:53:59.007 --> 00:54:04.296
다양한 종류의 건축물과 자동차도 나타났습니다.
모든 것들이 아주 흥미로운 결과입니다.

00:54:04.296 --> 00:54:08.743
나타난 특징들 중에 사람들이 이름을
지어낸 것들도 있습니다.

00:54:08.743 --> 00:54:12.133
아주 많이 나타난 것 중 하나가
"Admiral dog" 입니다.

00:54:12.133 --> 00:54:16.033
"돼지 달팽이 (pig snail), "낙타 새"(Camel-bird),
"개 물고기"(dog-fish) 도 있습니다.

00:54:16.033 --> 00:54:22.771
이 모든것들이 아주 흥미롭습니다만, 이러한 시각화에
"개" 가 아주 빈번하게 등장한다는 것은

00:54:22.771 --> 00:54:26.249
이 네트워크를 학습시킨 데이터와 관련이 있습니다.

00:54:26.249 --> 00:54:30.786
이 네트워크는 ImageNet Classification 데이터셋으로
학습시켰습니다. 1000개의 카테고리가 있습니다.

00:54:30.786 --> 00:54:32.915
그런데, 그 중 200개의 카테고리가 개입니다.

00:54:32.915 --> 00:54:44.027
따라서 시각화된 결과에
"개"와 관련된 것들이 자주 나오는 것은 당연합니다.

00:54:44.027 --> 00:54:47.327
그리고 다른 레이어를 가지고 만들어보면
색다른 결과를 보실 수도 있습니다.

00:54:47.327 --> 00:54:52.708
이 예제의 경우 더 얕은 층의 레이어로 만든 이미지입니다.
앞서 보여드린 예제가 조금 더 깊은 층의 레이어로 만들었었죠

00:54:52.708 --> 00:54:57.791
더 얕은 층으로 만들어보면, 엣지나, 소용돌이 무늬와
같은 것들을이 보입니다.

00:54:57.791 --> 00:55:01.766
얕은 레이어로 DeepDream을 수행하면 보이는 것들입니다.

00:55:01.766 --> 00:55:08.346
DeepDream에 멀티 스케일을 가미해서 오랫동안 돌려보면
다음과 같은 아주아주 놀라운 것들을 볼 수 있습니다.

00:55:08.346 --> 00:55:14.631
여기에서는 멀티 스케일 프로세싱을 수행합니다. 작은 이미지로
DeepDream을 수행하고 점점 이미지 크기를 늘려나갑니다.

00:55:14.631 --> 00:55:19.893
이런 식으로 점점 더 큰 이미지에 DeepDream을 수행하는
반복적인 과정을 거치는데,

00:55:19.893 --> 00:55:25.699
가장 큰 최종 스케일로 수행하고 나면 다시
처음부터 이 과정을 반복 수행합니다.

00:55:25.699 --> 00:55:28.126
그 결과 이런 놀라운 이미지를 얻을 수 있습니다.

00:55:28.126 --> 00:55:31.454
지금 보시는 이미지는 ImageNet으로 학습시킨
네트워크로 만든 이미지입니다.

00:55:31.454 --> 00:55:35.216
다른 데이터셋으로도 만들어 볼 수 있습니다.
가령 MIT Paces Dataset으로도 해볼 수 있겠죠

00:55:35.216 --> 00:55:40.224
1,000 카테고리의 객체(ImageNet) 대신에
200가지의 다양한 장면을 가진 데이터셋입니다.

00:55:40.224 --> 00:55:42.663
이 데이터셋에는 가령 침실, 부엌 과 같은 장면이 있습니다.

00:55:42.663 --> 00:55:50.868
MIT place로 학습시킨 네트워크를 가지고 DeepDream을
수행하면, 이와 같은 멋있는 시각화 이미지를 얻을 수 있습니다.

00:55:50.868 --> 00:55:59.491
이제는 "개 달팽이, Admiral dogs" 와 같은 것들 대신에
일본식 건축물의 지붕과 같은 모양이라던지

00:55:59.491 --> 00:56:02.104
다양한 "다리(bridges)", "산맥(mountatin ranges" 과
같은 것들이 보입니다.

00:56:02.104 --> 00:56:05.288
아주 멋있고 아름다운 이미지들입니다.

00:56:05.288 --> 00:56:11.685
DeepDream의 코드를 Google이 온라인에 공개하였으니
여러분만의 아름다운 그림을 만들어보면 좋겠습니다.

00:56:11.685 --> 00:56:14.535
질문 있나요?

00:56:24.731 --> 00:56:28.252
질문은 "그레디언트를 어디에서 가져오는지" 입니다.

00:56:28.252 --> 00:56:33.318
앞서 말씀드렸듯, 1/(x^2)가 있을때
activation에 대한 그레디언트는 x입니다.

00:56:33.318 --> 00:56:44.477
따라서 그레디언트를 보낼때 activation 값 자체를 보내게
되면, 1/(x^2) 의 그레디언트를 계산하는 것과 동치입니다.

00:56:44.477 --> 00:56:49.665
그리고 이는 해당 레이어의 특징들(activations)의
norm을 최대화시키는 것과 동치입니다.

00:56:49.665 --> 00:56:56.511
하지만 대부분의 실제 구현은 이를 명시적으로 계산하지는 않고
그레디언트만 뒤로 보내줍니다.

00:56:56.511 --> 00:57:01.478
Feature inversion 이라는 아주 유용한 개념이 있습니다.

00:57:01.478 --> 00:57:07.687
이 방법 또한 네트워크의 다양한 레이어에서 이미지의
어떤 요소들을 포착하고 있는지를 짐작할 수 있게 해줍니다.

00:57:07.687 --> 00:57:12.220
방법은 다음과 같습니다. 어떤 이미지가 있고,
이 이미지를 네트워크에 통과시킵니다.

00:57:12.220 --> 00:57:15.832
그리고 네트워크를 통과시킨
특징(activation map)을 저장해둡니다.

00:57:15.832 --> 00:57:20.283
그리고 이제는 이 특징(activation map) 만 가지고
이미지를 재구성해 볼 것입니다.

00:57:20.283 --> 00:57:31.074
해당 레이어의 특징 벡터로부터 이미지를 재구성해보면, 이미지의
어떤 정보가 특징 벡터에서 포착되는지를 짐작할 수 있을 것입니다.

00:57:31.074 --> 00:57:34.191
이 방법에서 또한 regularizer를 추가한
gradient ascent를 이용합니다.

00:57:34.191 --> 00:57:41.709
스코어를 최대화시키는 것 대신, 특징 벡터간의
거리를 최소화시키는 방법을 이용합니다.

00:57:41.709 --> 00:57:50.014
기존에 계산해 놓은 특징 벡터와, 새롭게 생성한 이미지로
계산한 특징벡터 간의 거리를 측정하는 것입니다.

00:57:50.014 --> 00:57:56.856
여러분이 과제에서 보겠지만, 여기 사람들이 자주 사용하는
regularizer인 total vatication이 있습니다.

00:57:56.856 --> 00:58:05.954
Total variation regularizer은 상하좌우 인접 픽셀 간의
차이에 대한 패널티를 부여합니다.

00:58:05.954 --> 00:58:09.956
생성된 이미지가 자연스러운 이미지가 되도록 해줍니다.

00:58:09.956 --> 00:58:16.369
Feature inversion을 통한 시각화 예제를 살펴봅시다.
왼쪽은 원본 이미지입니다.

00:58:16.369 --> 00:58:18.294
코끼리 이미지와 과일 이미지가 있습니다.

00:58:18.294 --> 00:58:22.458
이 이미지를 VGG-16에 통과시켜봅시다.

00:58:22.458 --> 00:58:30.013
그리고 특징 맵을 기록하고, 기록된 특징 맵과 부합하도록
하는 새로운 이미지를 합성합니다.

00:58:30.013 --> 00:58:37.534
다양한 레이어를 이용해서 합성한 이미지들을 통해서,
얼마나 많은 정보들이 저장되어 있는지를 짐작해 볼 수 있습니다.

00:58:37.534 --> 00:58:43.849
가령 VGG-16 의 relu2_2를 거쳐서 나온 특징 벡터를
가지고 이미지를 재구성해보면

00:58:43.849 --> 00:58:46.628
이미지가 거의 완벽하게 재구성됨을 알 수 있습니다.

00:58:46.628 --> 00:58:52.664
이를 통해, relu2_2 에서는 이미지 정보를
엄청 많이 날려버리지는 않는다는 사실을 알 수 있습니다.

00:58:52.664 --> 00:58:58.593
자 그럼 이제 네트워크의 조금 더 깊은 곳을 살펴봅시다.
relu4_3 과 relu5_1을 가지고 재구성해 보겠습니다.

00:58:58.593 --> 00:59:05.488
재구성된 이미지를 보면 이미지의 공간적인 구조는
잘 유지하고 있다는 것을 알 수 있습니다.

00:59:05.488 --> 00:59:09.684
재구성된 이미지만 봐도 코끼리인지, 바나나인지, 사과인지
우리 눈으로도 구별할 수 있습니다.

00:59:09.684 --> 00:59:16.427
하지만 디테일은 많이 죽었습니다. 정확히 어떤 픽셀인지,
어떤 색인지, 텍스터가 정확히 어떤지를 알아보기 힘듭니다.

00:59:16.427 --> 00:59:20.923
그런 낮은 레벨의 디테일들은 네트워크가
깊어질수록 손질됨을 알 수 있습니다.

00:59:20.923 --> 00:59:29.153
이를 통해서, 네트워크가 깊어질수록 픽셀 값이 정확히
얼마인지 와 같은 저 수준의 정보들은 전부 사라지고, 대신에

00:59:29.153 --> 00:59:38.109
색이나 텍스처와 같은 미세한 변화에 더 강인한
의미론적 정보들만을 유지하려 하는 것일지 모릅니다.

00:59:38.109 --> 00:59:42.835
우리는 지금까지 계속 Style transfer를
배우기 위한 준비단계에 있습니다.

00:59:42.835 --> 00:59:51.029
Style transfer와 feature inversion 외에도
텍스처 합성과 관련된 문제들도 살펴볼 필요가 있습니다.

00:59:51.029 --> 00:59:55.112
텍스처 합성 문제는 컴퓨터 그래픽스 분야에서는
아주  오래된 문제입니다.

00:59:55.112 --> 01:00:05.792
문제는, 가령 여기 보이시는 비늘 무늬와 같은 입력 텍스처 패치가
있을 때, 동일한 텍스처인 더 큰 패치를 생성하는 것입니다.

01:00:05.792 --> 01:00:12.056
가령 여기 보시는 그림과 같이 입력 패치와 비슷한
비늘 패턴을 가진 더 큰 이미지를 생성하는 것입니다.

01:00:12.056 --> 01:00:15.986
다시 말씀드리지만 텍스처 합성은
컴퓨터 그래픽스에서 아주 오래된 문제입니다.

01:00:15.986 --> 01:00:19.720
nearest neighbor를 통한 텍스처 합성 방법들도
상당히 좋은 편입니다.

01:00:19.720 --> 01:00:21.659
이 방법에는 신경망을 사용하지 않죠

01:00:21.659 --> 01:00:27.792
이 간단한 알고리즘은 신경망 대신에 scan line을 따라서
한 픽셀씩 이미지를 생성해 나가는 방식입니다.

01:00:27.792 --> 01:00:34.742
이 방법은 현재 생성해야 할 픽셀 주변의
이미 생성된 픽셀들을 살펴봅니다.

01:00:34.742 --> 01:00:41.934
그리고 입력 패치에서 가장 가까운 픽셀을 계산하여
입력 패치로부터 한 픽셀을 복사해 넣는 방식이죠

01:00:41.934 --> 01:00:48.889
더 자세히 알 필요는 없습니다. 텍스처 합성 문제를 위한
고전적인 방법들이 아주 많다는 사실만 알아두시면 됩니다.

01:00:48.889 --> 01:00:52.749
기본적으로 텍스처 합성은 신경망 없이도 할 수 있습니다.

01:00:52.749 --> 01:00:59.915
앞서 말씀드린 고전적인 방법들은 간단한 텍스처를
합성하는데는 큰 문제가 없습니다.

01:00:59.915 --> 01:01:08.970
하지만 조금 더 복잡한 텍스처에서는 상황이 조금 다릅니다.
단순하게 입력 패치에서 복사하는 방식은 잘 동작하지 않습니다.

01:01:08.970 --> 01:01:16.494
2015년에 신경망을 활용해서 텍스처 합성 문제는
푸려는 시도가 처음 있었습니다.

01:01:16.494 --> 01:01:24.753
이 방법은 우리가 앞서 살펴본 특징 맵을 이용한
gradient ascent 방법도 상당히 유사합니다.

01:01:24.753 --> 01:01:30.558
이 방법은 Neural texture synthesis 를 구현하기 위해서
Gram matrix라는 개념을 이용합니다.

01:01:30.558 --> 01:01:36.372
이 방법에서는, 가령 여기 입력 텍스처로 자갈 사진이 있습니다.

01:01:36.372 --> 01:01:44.347
이 사진을 네트워크에 통과시킨 후, 네트워크의 특정
레이어에서 특징 맵을 가져옵니다.

01:01:44.347 --> 01:01:53.596
이렇게 가져온 특징 맵의 크기는 C x H x W 일 것입니다.

01:01:53.596 --> 01:01:56.515
H x W 그리드는 공간 정보는 가지고 있습니다.

01:01:56.515 --> 01:02:04.347
H x W 의 한 점에 있는 C차원 특징 벡터는 해당 지점에
존재하는 이미지의 특징을 담고 있다고 할 수 있습니다.

01:02:04.347 --> 01:02:10.179
이제 이 특징 맵을 가지고 입력 이미지의 텍스트
기술자(descriptor)를 계산할 것입니다.

01:02:10.179 --> 01:02:15.294
우선 특징 맵에서 서로 다른 두 개의 특징 벡터를 뽑아냅니다.
(빨간 색, 파란 색)

01:02:15.294 --> 01:02:18.318
각 특징 열 벡터는 C차원 벡터입니다.

01:02:18.318 --> 01:02:23.390
이 두 벡터의 외적(outer product)을 계산해서
C x C 행렬을 만듭니다.

01:02:23.390 --> 01:02:30.333
이 C x C 행렬은 이미지 내 서로 다른 두 지점에 있는
특징들 간의  co-occurrence를 담고 있습니다.

01:02:30.333 --> 01:02:40.218
가령 C x C 행렬의 (i, j) 번째 요소의 값이 크다는 것은
두 입력 벡터의 i번째, j번째 요소가 모두 크다는 의미입니다.

01:02:40.218 --> 01:02:51.572
이를 통해 서로 다른 공간에서 동시에 활성회되는 특징이 무엇인지
2차 모멘트를 통해 어느정도 포착해 낼 수 있는 것입니다.

01:02:51.572 --> 01:03:01.664
이 과정을 H x W 그리드에서 전부 수행해주고, 결과에 대한
평균을 계산해보면 C x C Gram matrix를 얻을 수 있습니다.

01:03:01.664 --> 01:03:06.323
그리고 이 결과를 입력 이미지의 텍스처를
기술하는 텍스처 기술자로 사용합니다.

01:03:06.323 --> 01:03:13.623
Gram matrix의 흥미로운 점은
공간 정보를 모두 날려버렸다는 것입니다.

01:03:13.623 --> 01:03:17.545
이미지의 각 지점에 해당하는 값들을
모두 평균화 시켰기 떄문입니다.

01:03:17.545 --> 01:03:21.863
공간 정보를 다 날려버린 대신에 특징들 간의
co-occurrence 만을 포착해 내고 있습니다.

01:03:21.863 --> 01:03:25.364
때문에 gram matrix는 텍스처 기술자로 아주 제격입니다.

01:03:25.364 --> 01:03:27.640
또한 계산도 아주 효율적입니다.

01:03:27.640 --> 01:03:39.682
C x H x W 차원의 3차원 텐서가 있다고 해도 행렬을 C x
(HW)로 바꾼 다음에 한 번에 계산할 수 있습니다. 매우 효율적입니다.

01:03:39.682 --> 01:03:45.417
혹시, 왜 제대로된 공분산 행렬을 쓰지 않고
이런 허접한 gram matrix를 사용하는지 궁금하실 수도 있습니다.

01:03:45.417 --> 01:03:51.845
물론 공분산 행렬을 써도 무방하고, 실제로 동작도 잘 합니다.
하지만 공분한 행렬을 계산하는 것 자체가 비용이 너무 큽니다.

01:03:51.845 --> 01:03:55.203
따라서 실제로 사람들은 공분산 행렬 보다는
gram matrix를 선호하는 편입니다.

01:03:55.203 --> 01:04:06.916
자 이제 텍스처 기술자를 만들었으니 이미지를 생성할 차례입니다.
이는 gradient ascent procedure와 유사한 과정을 거칩니다.

01:04:06.916 --> 01:04:10.913
텍스처 합성도, 앞서 슬라이드에서 접했던
특징 재구성(feature reconstruction)와 유사합니다.

01:04:10.913 --> 01:04:20.883
다만 입력 이미지의 특징맵 전체를 재구성하기 보다는
gram matrix를 재구성하도록 하는 것입니다.

01:04:20.883 --> 01:04:25.969
실제로 거치는 단계는, 우선 pretrained model를
다운로드 받습니다. feature inversion에서 했던 것 처럼.

01:04:25.969 --> 01:04:28.720
많은 사람들이  VGG 네트워크를 선호합니다.

01:04:28.720 --> 01:04:38.553
그리고 이미지를 VGG에 통과시키고
다양한 레이어에서 gram matrix를 계산합니다.

01:04:38.553 --> 01:04:47.414
그리고 생성해야 할 이미지를 랜덤으로 초기화시키고,
그 다음 과정 부터는  gradient ascent와 유사합니다.

01:04:47.414 --> 01:04:52.530
다시, 우선 이미지를 VGG에 통과시킵니다.
그리고 여러 레이어에서 gram matrix를 계산합니다.

01:04:52.530 --> 01:05:00.833
그리고 원본 이미지와 생성된 이미지의 gram matrix
간의 차이를 L2 norm을 이용해 Loss로 계산합니다.

01:05:00.833 --> 01:05:06.025
그리고 Loss를 backprob을 통해 생성된 이미지의 픽셀의
그레디언트를 계산합니다.

01:05:06.025 --> 01:05:09.273
그리고 gradient ascent 를 통해
이미지의 픽셀을 조금씩 업데이트 합니다.

01:05:09.273 --> 01:05:17.071
이 단계을 여러번 반복합니다. 다시 앞 단계로 가서
gram matrix를 계산하고, Loss를 계산하고 backprob합니다.

01:05:17.071 --> 01:05:22.702
이 과정을 거치면 결국 입력 텍스처와 유사한
아주 잘 텍스처를 만들어낼 수 있습니다.

01:05:22.702 --> 01:05:30.022
NIP'15에 실린 논문은 독일의 한 연구소에서 나왔습니다.
텍스처 합성 결과가 아주 뛰어납니다.

01:05:30.022 --> 01:05:33.531
맨 위 이미지를 보시면 네가지의 서로 다른 입력
텍스처를 보실 수 있습니다.

01:05:33.531 --> 01:05:41.133
그리고 아래 쪽은 gram matix를 이용한
텍스터 합성을 보여줍니다.

01:05:41.133 --> 01:05:45.681
pretrained CNN의 다양한 레이어에서 gram matrix
를 계산한 결과입니다.

01:05:45.681 --> 01:05:56.965
얕은 레이어에서의 결과를 보면, 얼룩 얼룩한 이미지가 색상은
잘 유지하고 있지만 공간적인 구조는 잘 살리지 못합니다.

01:05:56.965 --> 01:06:06.935
레이어가 더 깊어질수록, 이미지의 더 큼지막한 패턴들을
아주 잘 재구성해 내는 것을 보실 수 있습니다.

01:06:06.935 --> 01:06:10.107
가령 여기 자갈이나 크렌베리를 보면 아주 잘 만들어졌죠

01:06:10.107 --> 01:06:17.677
결과가 상당히 좋습니다. 입력 패치의 패턴과 아주 유사한
새로운 이미지를 아주 잘 합성해 낼 수 있습니다.

01:06:17.677 --> 01:06:21.445
앞서 보여드린 고전적인 픽셀 기반의 방법과는
확연히 다른 결과들을 보실 수 있습니다.

01:06:21.445 --> 01:06:22.528
질문 있나요?

01:06:28.481 --> 01:06:30.847
질문은 "보통 Loss를 어느 레이어에서 계산하는지" 입니다.

01:06:30.847 --> 01:06:40.285
일반적으로는 gram matrix를 다양한 레이어에서 계산하고
가중 합을 통해 최종 loss를 구합니다.

01:06:40.285 --> 01:06:47.940
현재 보시는 슬라이드의 경우에는, 각 레이어의 특징을 강조하기
위해서, 오로지 한 레이어로만 gram matrix를 계산한 것입니다.

01:06:47.940 --> 01:06:52.999
이 논문 이후로 아주 놀라운 아이디어가 등장하게 됩니다.

01:06:52.999 --> 01:07:01.417
이 텍스처 합성을 자갈이나 크렌베리가 아니라
예술작품에 적용하면 어떻게 될까요?

01:07:01.417 --> 01:07:03.748
그래서, 예를 들어, 당신이...

01:07:03.748 --> 01:07:10.333
자 우선, gram matrix를 이용한 텍스처 합성은 그대로 가져갑니다.

01:07:10.333 --> 01:07:14.656
여기에 Starry night(Van Gogh) 이나 Muse(Picasso)
를 텍스처 입력으로 사용하면 어떻게 될까요?

01:07:14.656 --> 01:07:19.759
이들을 입력 텍스처로 두고 같은 알고리즘을 수행합니다.

01:07:19.759 --> 01:07:25.683
생성된 이미지를 보면, 이들은 예술 작품의
아주 흥미로운 부분들을 재구성해 내는 경향을 알 수 있습니다.

01:07:25.683 --> 01:07:34.616
texture synthesis와 feature inversion 을 조합하면
아주 흥미로운 일이 벌어집니다.

01:07:34.616 --> 01:07:38.988
아 아이디어가 바로 style transfer 입니다.

01:07:38.988 --> 01:07:42.716
Style transfer에서는 입력이 두가지입니다.

01:07:42.716 --> 01:07:49.813
Content Image는 네트워크에게 우리의 최종 이미지가
어떻게 "생겼으면 좋겠는지" 를 알려줍니다.

01:07:49.813 --> 01:07:55.499
Style Image는 최종 이미지의
"텍스처가 어땠으면 좋겠는지" 을 알려줍니다.

01:07:55.499 --> 01:08:02.596
최종 이미지는 content image의 feature
reconstruction loss도 최소화하고(1),

01:08:02.596 --> 01:08:05.661
Style image의 gram matrix loss도 최소화하는
방식으로 최적화하여 생성해 냅니다.

01:08:05.661 --> 01:08:14.353
이 두가지 Loss를 동시에 활용하면, style image 스러운
화풍의 content image가 생성됩니다.

01:08:14.353 --> 01:08:18.317
아주 멋있는 결과입니다.
아주 아름다운 이미지를 얻을 수 있습니다.

01:08:18.317 --> 01:08:26.384
네트워크에 content/style 이미지를 네트워크에 통과시키고
gram matrix와 feature map을 계산합니다.

01:08:26.384 --> 01:08:29.332
최종 출력 이미지는 랜덤 노이즈로 초기화시킵니다.

01:08:29.332 --> 01:08:38.264
forward/backward를 반복하여 계산하고 gradient ascent
를 이용해서 이미지를 업데이트합니다.

01:08:38.265 --> 01:08:43.247
수 백번정도 반복하면 아주 아름다운 이미지를
얻을 수 있게 됩니다.

01:08:43.247 --> 01:08:48.965
제 github에 실제 구현이 있습니다. 사람들이 많이
사용하는데요, 아주 멋집니다.

01:08:48.965 --> 01:08:54.609
Style Transfer는 DeepDream에 비해서
이미지를 생성할 때 컨트롤할 만한 것들이 더 많습니다.

01:08:54.609 --> 01:09:00.544
DeepDream의 경우에는 어떤 것들을 만들어낼지
컨트롤할 만한 요소가 많이 부족합니다.

01:09:00.544 --> 01:09:06.500
네트워크에 레이어와 반복 횟수정도만 조절하면
"개 달팽이(dog slug)"가 이미지 전체에 퍼질 뿐입니다.

01:09:06.500 --> 01:09:11.228
반면 Style Transfer의 경우 원하는 결과를 만들기 위해
정밀 조절한 것들이 조금 더 많습니다.

01:09:11.228 --> 01:09:19.099
동일한 content image라고 할지라도 다양한 style images
를 고르게 되면 전혀 다른 이미지들이 생성됩니다.

01:09:19.099 --> 01:09:30.349
하이퍼파라미터도 자유롭게 조정할 수 있습니다.
style/content loss의 joint loss이기 때문이죠

01:09:30.350 --> 01:09:39.468
style/content loss간의 가중치를 조절하면, 내가 어디에
더 집중해서 만들 것인지를 조절할 수 있습니다.

01:09:39.469 --> 01:09:41.647
또 다른 하이퍼파라이터도 존재합니다.

01:09:41.647 --> 01:09:45.707
가령 gram matrix를 계산하기 앞서
style image를 리사이징 해서 넣어준다면

01:09:45.707 --> 01:09:52.344
Style image로부터 재구성된 특징들의 스케일을
여러분 마음대로 조절할 수 있을 것입니다.

01:09:52.344 --> 01:09:58.976
여기 보이는 이미지들은 다른 것들은 전부 같은 세팅이고
다만 style image의 사이즈만 달라진 경우입니다.

01:09:58.976 --> 01:10:04.263
Style image의 사이즈를 조절하는 것이
조절할 수 있는 또 하나의 축이 될 수 있습니다.

01:10:04.263 --> 01:10:07.670
또한 여러 장의 style images를 가지고
style transfer를 할 수도 있습니다.

01:10:07.670 --> 01:10:13.431
동시에 여러 style loss의 gram matrix를 계산하는 것입니다.
결과도 아주 좋습니다.

01:10:13.431 --> 01:10:25.105
앞서 DeepDream에서 multi-scale processing을 통해
아주 멋진 고해상도 이미지를 얻을 수 있었습니다.

01:10:25.105 --> 01:10:29.330
multi-scale processing을 style transfer에도
적용해 볼 수 있습니다.

01:10:29.330 --> 01:10:40.867
이 이미지는 Starry night로 랜더링된
4K Stanford 이미지입니다.

01:10:40.867 --> 01:10:42.652
사실 고해상도 이미지를 만드는 것은
계산량이 상당합니다.

01:10:42.652 --> 01:10:47.074
4K 이미지를 위해 GPU 네 개를 사용했습니다.
아주 비싼 연산입니다.

01:10:47.074 --> 01:10:53.666
이는 동일한 content image를 가지고 다른 style
image를 적용한 것입니다. 고해상도죠

01:10:53.666 --> 01:11:01.168
또 다른 재밌는 방법도 있습니다. 사실 Style Transfer와
DeepDream을 조합해 볼 수도 있습니다.

01:11:01.168 --> 01:11:09.017
content loss + style loss + deepdream loss(
norm 최대화) 를 조합하는 것입니다.

01:11:09.017 --> 01:11:14.286
결과는 다음과 같습니다. "개 달팽이(dog slug)" 가
사방에 퍼져있는 Van Gogh 그림입니다.

01:11:14.286 --> 01:11:15.858
[웃음]

01:11:15.858 --> 01:11:18.466
아주 재밌습니다.

01:11:18.466 --> 01:11:23.012
Style Stranfer 알고리즘의 가장 큰 단점은
아주 느리다는 것입니다.

01:11:23.012 --> 01:11:30.164
이런 이미지를 만들어 내려면 backward/forward를
아주 많이 반복해야 합니다.

01:11:30.164 --> 01:11:38.200
게다가 앞서 보여드린 4K 이미지를 만드려면
메모리와 계산량이 엄청나게 큽니다.

01:11:38.200 --> 01:11:46.340
엄청 좋은 GPU를 쓰더라도 이미지 한장을
만드는데 수십 분이 요소됩니다.

01:11:46.340 --> 01:11:50.320
따라서 실제로 적용하기는 힘듭니다.

01:11:50.320 --> 01:11:54.874
해결책이 있다면, Style tranfer를 위한
또 다른 네트워크를 학습시키는 것입니다.

01:11:54.874 --> 01:12:03.164
2016년에 나온 논문입니다. 애초에 Style image를
고정시켜 놓습니다. 이 경우 Starry night 입니다.

01:12:03.164 --> 01:12:08.034
이 방법은 합성하고자 하는 이미지의 최적화를
전부 수행하는 것이 아니라

01:12:08.034 --> 01:12:15.748
Content image만을 입력으로 받아서
결과를 출력할 수 있는 단일 네트워크를 학습시키는 방법입니다.

01:12:15.748 --> 01:12:26.848
이 네트워크의 학습 시에는, content/style loss를
동시에 학습시키고 네트워크의 가중치를 업데이트합니다.

01:12:26.848 --> 01:12:36.148
학습은 몇 시간이 걸릴 수 있지만, 한번 학습시키고 나면
이미지를 네트워크에 통과시키면 결과가 바로 나올 수 있습니다.

01:12:36.148 --> 01:12:49.880
이 코드는 온라인에 있습니다. 영상 퀄리티는 기존의
방법과 거의 유사하면서도, 몇천배 빠르게 동작합니다.

01:12:49.880 --> 01:12:54.990
여러분이 보고계신 이 데모는 제가 웹캠으로
직접 돌려본 것입니다.

01:12:54.990 --> 01:13:05.476
이 네트워크가 아주 효율적이기 때문에 좋은 GPU을 사용하면
네 가지 스타일을 동시에 돌려볼 수도 있을 것입니다.

01:13:05.476 --> 01:13:12.650
러시아에서 나온 논문도 있습니다. 유사한 논문이고
결과도 아주 좋습니다.

01:13:12.650 --> 01:13:15.392
알고리즘을 조금 변형한 방법도 있습니다.

01:13:15.392 --> 01:13:25.450
앞서 보여드린 이 네트워크는 앞서 배웠던 세그멘데이션
네트워크와도 아주 유사하게 생겼습니다.

01:13:25.450 --> 01:13:37.678
Sementic segmentation 에서는 다운 샘플링을 여러 번 진행하고
transposed conv로 업샘플링을 합니다.

01:13:37.678 --> 01:13:45.244
Segmentic segmentation과 다른 점이라고는 출력이
RGB 이미지라는 점입니다.

01:13:45.244 --> 01:13:48.540
그리고 네트워크 중간에 batch norm이 들어갑니다.

01:13:48.540 --> 01:13:56.027
이 논문에서는 batch norm 대신에 instance norm을
사용해서 더 좋은 결과를 끌어냈습니다.

01:13:56.027 --> 01:14:05.500
지금까지 말씀드린 방식들의 단점이 있다면 네트워크 하나당
하나의 Style Transfer 밖에 할 수 덦다는 점입니다.

01:14:05.500 --> 01:14:10.433
다양한 Style을 위해서 서로 다른 네트워크를 만드는
일은 상당히 비용이 큰 작업입니다.

01:14:10.433 --> 01:14:21.178
아주 최근에 Google 에서 나온 논문은, 하나의 네트워크로
다양한 Style을 생성해낼 수 있는 방법을 제안했습니다.

01:14:21.178 --> 01:14:28.034
하나의 네트워크만 학습시켜서 다양한 Style result를
만들어낼 수 있는 방법입니다.

01:14:28.034 --> 01:14:36.477
네트워크 입력으로 content image와 style image를 동시에
넣는 방식을 통해서 다양한 스타일을 만들어낼 수 있습니다.

01:14:36.477 --> 01:14:39.365
이 네트워크 또한 실시간으로 동작할 수 있습니다.

01:14:39.365 --> 01:14:44.442
동일한 알고리즘은 하나의 네트워크 만으로
실시간 style blending 또한 가능합니다.

01:14:44.442 --> 01:14:52.458
네 가지 서로 다른 style을 학습시키면 이 네 가지
style을 섞어버릴 수도 있습니다.

01:14:52.458 --> 01:15:01.976
이러한 종류의 real-time style transfer 방법들은
아주 다양한 응용이 가능하며 실제로 많이 사용되고 있습니다.

01:15:01.976 --> 01:15:04.071
오늘 배운 내용을 요약해봅시다.

01:15:04.071 --> 01:15:08.113
우리는 오늘 CNN representations을 이해할
수있는 다양한 방법들을 배웠습니다.

01:15:08.113 --> 01:15:10.190
우선 activation 기반의 방법들이 있었습니다.

01:15:10.190 --> 01:15:14.220
nearest neighbor, dimensionality reduction
maximal patches, occlusion images 등이죠

01:15:14.220 --> 01:15:18.316
Activation values를 기반으로 해당 특징이
무엇을 찾고있는지를 이해하는 방법이었습니다.

01:15:18.316 --> 01:15:20.461
우리는 또한 gradient 기반의 방법도 배웠습니다.

01:15:20.461 --> 01:15:27.127
gradients을 이용해서 새로운 이미지를 만들어내는 방법이었습니다.

01:15:27.127 --> 01:15:30.417
saliency maps, class visualizations,
fooling images, feature inversion이 있었죠

01:15:30.417 --> 01:15:37.997
그리고 아주 멋있는 이미지들을 생성해내는
Style Transfer/DeepDream을 알아보았습니다.

01:15:37.997 --> 01:15:40.397
다음 시간에는 unsupervised learning에
대해서 배워보겠습니다.

01:15:40.397 --> 01:15:45.834
Autoencoders, Variational Autoencoders(VAE),
generative adversarial networks(GAN) 을 배워보겠습니다.